package com.xbongbong.saas.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.i18n.util.I18nMessageUtil;
import com.xbongbong.paas.business.rule.RuleBusinessLogger;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.domain.entity.PaasFormDataEntity;
import com.xbongbong.paas.domain.entity.PaasFormExplainEntity;
import com.xbongbong.paas.domain.entity.ext.ConditionsEntityExt;
import com.xbongbong.paas.domain.entity.ext.PaasFormDataEntityExt;
import com.xbongbong.paas.domain.entity.ext.PaasFormEntityExt;
import com.xbongbong.paas.elasticsearch.model.PaasEsModel;
import com.xbongbong.paas.elasticsearch.pojo.XbbAggregatedPage;
import com.xbongbong.paas.elasticsearch.util.EsHelper;
import com.xbongbong.paas.elasticsearch.util.EsUtil;
import com.xbongbong.paas.elasticsearch.util.XbbElasticsearchRestTemplate;
import com.xbongbong.paas.enums.DelEnum;
import com.xbongbong.paas.enums.FieldTypeEnum;
import com.xbongbong.paas.enums.FlowStatusEnum;
import com.xbongbong.paas.enums.IndexTypeEnum;
import com.xbongbong.paas.enums.PaymentSheetTypeEnum;
import com.xbongbong.paas.field.DefaultAttrPoJo;
import com.xbongbong.paas.field.FieldAttrEntity;
import com.xbongbong.paas.help.CommonHelp;
import com.xbongbong.paas.help.PaasFormHelp;
import com.xbongbong.paas.help.ProSaveHelp;
import com.xbongbong.paas.help.ProUpdateHelp;
import com.xbongbong.paas.help.TransactionHelp;
import com.xbongbong.paas.log.MongoLogHelp;
import com.xbongbong.paas.log.constant.LogMemoConstant;
import com.xbongbong.paas.log.pojo.InfoArrPojo;
import com.xbongbong.paas.model.PaasFormExplainModel;
import com.xbongbong.paas.model.PaasProcessTemplateModel;
import com.xbongbong.paas.pojo.ButtonPojo;
import com.xbongbong.paas.pojo.FieldAttrEntityForImport;
import com.xbongbong.paas.pojo.FormTitlePoJo;
import com.xbongbong.paas.pojo.SummaryDataPoJo;
import com.xbongbong.paas.pojo.dto.FormDataAddDTO;
import com.xbongbong.paas.pojo.dto.FormDataDeleteBatchDTO;
import com.xbongbong.paas.pojo.dto.FormDataListDTO;
import com.xbongbong.paas.pojo.dto.ImportFormDataDTO;
import com.xbongbong.paas.pojo.dto.SaasFormSaveDTO;
import com.xbongbong.paas.pojo.dto.ValidateDataDTO;
import com.xbongbong.paas.pojo.imports.CellTitlePojo;
import com.xbongbong.paas.pojo.imports.CellValuePojo;
import com.xbongbong.paas.pojo.imports.RowGroupPojo;
import com.xbongbong.parent.interfaces.DynamicStrategy;
import com.xbongbong.paas.service.dynamic.crm.strategy.DynamicStrategyFactory;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.helper.PageHelper;
import com.xbongbong.paas.toolbox.util.Arith;
import com.xbongbong.paas.toolbox.util.BeanUtil;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.paas.toolbox.util.DateUtil;
import com.xbongbong.paas.toolbox.util.MoneyUtil;
import com.xbongbong.paas.toolbox.util.PageHelperUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.paas.toolbox.wrap.UserVO;
import com.xbongbong.paas.util.ExplainUtil;
import com.xbongbong.pro.applist.pojo.AppListPojo;
import com.xbongbong.pro.applist.pojo.vo.ListAppVO;
import com.xbongbong.pro.businessdata.pojo.dto.FormatExplainDTO;
import com.xbongbong.pro.constant.CommonConstant;
import com.xbongbong.pro.constant.ElasticConstant;
import com.xbongbong.pro.customer.pojo.dto.CustomerRestoreBatchDTO;
import com.xbongbong.pro.domain.entity.UpdateDataEntity;
import com.xbongbong.pro.dynamic.pojo.dto.DynamicDeleteDTO;
import com.xbongbong.pro.dynamic.pojo.dto.DynamicSaveDTO;
import com.xbongbong.pro.enums.DistributorMarkEnum;
import com.xbongbong.pro.enums.SaasMarkEnum;
import com.xbongbong.pro.enums.errorcodes.InvoiceErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.TemplateErrorCodeEnum;
import com.xbongbong.pro.enums.fund.enums.ModelTypeEnum;
import com.xbongbong.pro.enums.permission.enums.ProPermissionAliasEnum;
import com.xbongbong.pro.formdata.pojo.SaasNeedRedundantAttrPojo;
import com.xbongbong.pro.formexplain.pojo.dto.HandlerExplainBatchLinkItemDTO;
import com.xbongbong.pro.formexplain.pojo.dto.HandlerExplainInLinkItemDTO;
import com.xbongbong.pro.invoice.pojo.InvoiceCancelOrRestorePojo;
import com.xbongbong.pro.invoice.pojo.InvoiceCommonSavePojo;
import com.xbongbong.pro.invoice.pojo.InvoiceRelationshipEditPojo;
import com.xbongbong.pro.invoice.pojo.RefTypePojo;
import com.xbongbong.pro.invoice.pojo.dto.CheckRedInvoiceDeletePojo;
import com.xbongbong.pro.invoice.pojo.dto.ComputeInvoiceAmountDTO;
import com.xbongbong.pro.invoice.pojo.dto.CustomerInvoiceAndExpressGetDTO;
import com.xbongbong.pro.invoice.pojo.dto.InvoiceAmountDetailGetDTO;
import com.xbongbong.pro.invoice.pojo.dto.InvoiceDeleteBatchDTO;
import com.xbongbong.pro.invoice.pojo.dto.InvoiceEditAttrUpdateDTO;
import com.xbongbong.pro.invoice.pojo.dto.InvoiceGetByContractDTO;
import com.xbongbong.pro.invoice.pojo.dto.InvoiceUpdateBatchDTO;
import com.xbongbong.pro.invoice.pojo.dto.InvoiceUpdateByBusinessRuleDTO;
import com.xbongbong.pro.invoice.pojo.dto.InvoiceUpdateDTO;
import com.xbongbong.pro.invoice.pojo.vo.ComputeInvoiceAmountVO;
import com.xbongbong.pro.invoice.pojo.vo.CustomerInvoiceAndExpressGetVO;
import com.xbongbong.pro.invoice.pojo.vo.InvoiceAmountDetailVO;
import com.xbongbong.pro.invoice.pojo.vo.InvoiceDeleteBatchVO;
import com.xbongbong.pro.invoice.pojo.vo.InvoiceGetByCustomerVO;
import com.xbongbong.pro.invoice.pojo.vo.InvoiceUpdateByBusinessRuleVO;
import com.xbongbong.pro.invoicerelation.pojo.dto.InvoiceRelationshipDeleteBatchDTO;
import com.xbongbong.pro.listbatch.pojo.dto.AddLabelDTO;
import com.xbongbong.pro.log.pojo.dto.RuleBusinessLogDTO;
import com.xbongbong.pro.message.constant.InvoicePushConstant;
import com.xbongbong.pro.message.enums.PushTypeEnum;
import com.xbongbong.pro.message.help.PushHelper;
import com.xbongbong.pro.message.pojo.PushRefTypePojo;
import com.xbongbong.pro.message.pojo.dto.MessageRabbitMqDTO;
import com.xbongbong.pro.permission.pojo.dto.VerifyAddPermissionDTO;
import com.xbongbong.pro.rabbitmq.producer.BaseProducer;
import com.xbongbong.pro.service.toolbox.elasticsearch.help.ProEsHelper;
import com.xbongbong.pro.thread.ThreadPoolBeanConfig;
import com.xbongbong.saas.analytical.impl.InvoiceValidateAnalyticalServiceImpl;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.constant.ErrorMessageConstant;
import com.xbongbong.saas.constant.InvoiceConstant;
import com.xbongbong.saas.constant.PageConstant;
import com.xbongbong.saas.constant.ParameterConstant;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.domain.entity.CustomerExpressEntity;
import com.xbongbong.saas.domain.entity.CustomerInvoiceEntity;
import com.xbongbong.saas.domain.entity.InvoiceRelationshipEntity;
import com.xbongbong.saas.domain.entity.ext.ContractEntityExt;
import com.xbongbong.saas.domain.entity.ext.InvoiceEntityExt;
import com.xbongbong.saas.domain.entity.ext.PaymentEntityExt;
import com.xbongbong.saas.domain.entity.ext.PaymentSheetEntityExt;
import com.xbongbong.saas.enums.BusinessFieldEnum;
import com.xbongbong.saas.enums.CustomerExpressEnum;
import com.xbongbong.saas.enums.CustomerInvoiceEnum;
import com.xbongbong.saas.enums.OperateModuleTypeEnum;
import com.xbongbong.saas.enums.OperateTypeEnum;
import com.xbongbong.saas.enums.RedundantTemplateTypeEnum;
import com.xbongbong.saas.enums.SheetAloneEnum;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.enums.business.ContractEnum;
import com.xbongbong.saas.enums.business.CustomerManagementEnum;
import com.xbongbong.saas.enums.business.InvoiceEnum;
import com.xbongbong.saas.enums.business.PaymentEnum;
import com.xbongbong.saas.enums.business.PaymentRelationshipEnum;
import com.xbongbong.saas.enums.business.PaymentSheetEnum;
import com.xbongbong.saas.enums.business.RefTypeEnum;
import com.xbongbong.saas.enums.business.RefundEnum;
import com.xbongbong.saas.enums.dictionary.PaymentStatusEnum;
import com.xbongbong.saas.help.DefaultAttrHelp;
import com.xbongbong.saas.help.ExplainHelp;
import com.xbongbong.saas.help.FundHelp;
import com.xbongbong.saas.help.ImportHelper;
import com.xbongbong.saas.help.InvoiceCommonHelper;
import com.xbongbong.saas.help.InvoiceHelp;
import com.xbongbong.saas.help.LogHandleHelp;
import com.xbongbong.saas.help.ReceivablesHelper;
import com.xbongbong.saas.help.SaasDeleteHelp;
import com.xbongbong.saas.help.SaasInvoiceHelp;
import com.xbongbong.saas.help.SaasListHelp;
import com.xbongbong.saas.help.SaasSaveHelp;
import com.xbongbong.saas.help.SaasUpdateHelp;
import com.xbongbong.saas.model.ContractModel;
import com.xbongbong.saas.model.CustomerExpressModel;
import com.xbongbong.saas.model.CustomerInvoiceModel;
import com.xbongbong.saas.model.IndexTypeModel;
import com.xbongbong.saas.model.InvoiceModel;
import com.xbongbong.saas.model.InvoiceRelationshipModel;
import com.xbongbong.saas.model.PaymentModel;
import com.xbongbong.saas.model.PaymentSheetModel;
import com.xbongbong.saas.service.ContractService;
import com.xbongbong.saas.service.FundSetService;
import com.xbongbong.saas.service.InvoiceRelationshipService;
import com.xbongbong.saas.service.InvoiceService;
import com.xbongbong.saas.service.PaymentService;
import com.xbongbong.saas.service.PaymentSheetService;
import com.xbongbong.saas.service.toolbox.help.LogHelp;
import com.xbongbong.saas.service.toolbox.help.SaasListDataPermissionHelp;
import com.xbongbong.saas.toolbox.help.FastJsonHelper;
import com.xbongbong.sys.model.UserModel;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

import static com.xbongbong.paas.elasticsearch.constant.EsNormalConstant.MINI_MUM_SHOULD_MATCH;
import static com.xbongbong.saas.toolbox.help.FastJsonHelper.getDoubleOrDefaultFromFormData;
import static com.xbongbong.saas.toolbox.help.FastJsonHelper.getIntegerOrDefaultFromFormData;
import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
import static org.elasticsearch.index.query.QueryBuilders.matchPhraseQuery;
import static org.elasticsearch.index.query.QueryBuilders.rangeQuery;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
import static org.elasticsearch.index.query.QueryBuilders.termsQuery;

/**
 * 发票业务实现
 *
 * @author feng.zheng
 * @version v1.0
 * @date 2019/1/22 15:10
 * @since v1.0
 */
@Service("invoiceService")
public class InvoiceServiceImpl implements InvoiceService {

    private static final Logger LOG = LoggerFactory.getLogger(InvoiceServiceImpl.class);

    @Resource
    private SaasSaveHelp saasSaveHelp;
    @Resource
    private ExplainHelp explainHelp;
    @Resource
    private DefaultAttrHelp defaultAttrHelp;
    @Resource
    private SaasUpdateHelp saasUpdateHelp;
    @Resource
    private InvoiceModel invoiceModel;
    @Resource
    private ContractModel contractModel;
    @Resource
    private PaasEsModel paasEsModel;
    @Resource
    private PaymentModel paymentModel;
    @Resource
    private PaymentSheetModel paymentSheetModel;
    @Resource
    private InvoiceRelationshipModel invoiceRelationshipModel;
    @Resource
    private CustomerInvoiceModel customerInvoiceModel;
    @Resource
    private CustomerExpressModel customerExpressModel;
    @Resource
    private InvoiceRelationshipService invoiceRelationshipService;
    @Resource
    private EsHelper esHelper;
    @Resource
    private PushHelper pushHelper;
    @Resource
    private BaseProducer baseProducer;
    @Resource
    private ImportHelper importHelper;
    @Resource
    private CommonHelp commonHelp;
    @Resource
    private PaasProcessTemplateModel paasProcessTemplateModel;
    @Resource
    private MongoLogHelp mongoLogHelp;
    @Resource
    private ProEsHelper proEsHelper;
    @Resource
    private XbbElasticsearchRestTemplate xbbElasticsearchRestTemplate;
    @Resource
    @Lazy
    private RuleBusinessLogger ruleBusinessLogger;
    @Resource
    private PaasFormExplainModel paasFormExplainModel;
    @Resource
    private SaasListHelp saasListHelp;
    @Resource
    private SaasListDataPermissionHelp saasListDataPermissionHelp;
    @Resource
    private FundHelp fundHelp;
    @Resource
    private PaasFormHelp paasFormHelp;
    @Resource
    private InvoiceCommonHelper invoiceCommonHelper;
    @Resource
    private PaymentService paymentService;
    @Resource
    private FundSetService fundSetService;
    @Resource
    private ReceivablesHelper receivablesHelper;
    @Resource
    private ProUpdateHelp proUpdateHelp;
    @Resource
    private ThreadPoolBeanConfig threadPoolBeanConfig;
    @Resource
    private ContractService contractService;
    @Resource
    private PaymentSheetService paymentSheetService;
    @Resource
    private LogHelp logHelp;
    @Resource
    private LogHandleHelp logHandleHelp;
    @Resource
    private SaasInvoiceHelp saasInvoiceHelp;
    @Resource
    private InvoiceValidateAnalyticalServiceImpl invoiceAnalyticalService;
    @Resource
    private InvoiceHelp invoiceHelp;
    @Resource
    private IndexTypeModel indexTypeModel;

    @Resource
    private DynamicStrategyFactory dynamicStrategyFactory;
    @Resource
    private UserModel userModel;
    @Resource
    private TransactionHelp transactionHelp;

    /**
     * 发票保存前saas特殊校验
     *
     * @param validateDataDTO saas特殊校验数据入参
     * @throws XbbException 业务异常
     * @author feng.zheng
     * @date 2019/1/18
     */
    @Override
    public void beforeSave(ValidateDataDTO validateDataDTO) throws XbbException {
       invoiceAnalyticalService.beforeSave(validateDataDTO);
    }




    /**
     * 获取relationMap来判断金额
     *
     * @param isHasPayment 是否有回款
     * @param corpid       公司id
     * @param contractIds  合同集合
     * @param paymentOrSheetIds   回款集合
     * @return relationMap
     * @author feng.zheng
     * @date 2019/2/27 11:10
     */
    @Override
    public Map<String, Object> getRelationMapForJudgeMoney(boolean isHasPaymentSheet,boolean isPrePaymentSheet,boolean isPrePaymentSheetUnion,boolean isHasPayment,String corpid, List<Long> contractIds, List<Long> paymentOrSheetIds) throws XbbException {
        return saasInvoiceHelp.getRelationMapForJudgeMoney(isHasPaymentSheet, isPrePaymentSheet, isPrePaymentSheetUnion, isHasPayment, corpid, contractIds, paymentOrSheetIds);
    }







    private void onceMoreSetSizeInvoice(SaasNeedRedundantAttrPojo saasNeedRedundantAttrPojo,Map<String, Object> relationMap,JSONObject data,List<Long> contractIds,List<Long> refIds)throws XbbException{
        boolean isContractUnion = saasNeedRedundantAttrPojo.isContractUnion();
        boolean isPaymentUnion = saasNeedRedundantAttrPojo.isPaymentUnion();
        boolean isHasContract = saasNeedRedundantAttrPojo.isHasContract();
        boolean isHasPayment = saasNeedRedundantAttrPojo.isHasPayment();
        boolean isHasPaymentSheet = saasNeedRedundantAttrPojo.isHasPaymentSheet();
        boolean isPaymentSheetUnion = saasNeedRedundantAttrPojo.isPaymentSheetUnion();
        JSONArray contractArray = FastJsonHelper.getJsonArrOrDefaultFromFormData(data, InvoiceEnum.CONTRACT_ID.getAttr(), new JSONArray());
        JSONArray paymentArray = FastJsonHelper.getJsonArrOrDefaultFromFormData(data, InvoiceEnum.PAYMENT_ID.getAttr(), new JSONArray());
        JSONArray paymentSheetArray = FastJsonHelper.getJsonArrOrDefaultFromFormData(data,InvoiceEnum.PAYMENT_SHEET_ID.getAttr(),new JSONArray());
        Integer contractNum = contractArray.size();
        Integer paymentNum = paymentArray.size();
        Integer paymentSheetNum = paymentSheetArray.size();

        if(contractNum > BasicConstant.ZERO){
            isHasContract = true;
            isContractUnion = false;
            if(contractNum > BasicConstant.ONE){
                isContractUnion = true;
            }
        }else {
            isHasContract =false;
        }
        if (paymentNum > BasicConstant.ZERO) {
            isHasPayment = true;
            isContractUnion = false;
            isPaymentUnion = false;
            if (paymentNum > BasicConstant.ONE) {
                isPaymentUnion = true;
            }
        } else {
            isHasPayment = false;
        }
        if (paymentSheetNum > BasicConstant.ZERO) {
            isHasPaymentSheet = true;
            isContractUnion = false;
            isPaymentSheetUnion = false;
            if (paymentSheetNum > BasicConstant.ONE) {
                isPaymentSheetUnion = true;
            }
        } else {
            isHasPaymentSheet = false;
        }
        saasNeedRedundantAttrPojo.setContractUnion(isContractUnion);
        saasNeedRedundantAttrPojo.setPaymentUnion(isPaymentUnion);
        saasNeedRedundantAttrPojo.setHasContract(isHasContract);
        saasNeedRedundantAttrPojo.setHasPayment(isHasPayment);
        saasNeedRedundantAttrPojo.setHasPaymentSheet(isHasPaymentSheet);
        saasNeedRedundantAttrPojo.setPaymentSheetUnion(isPaymentSheetUnion);
        relationMap.put("contractNum",contractNum);
        relationMap.put("paymentNum",paymentNum);
        relationMap.put("paymentSheetNum",paymentSheetNum);

        contractIds.clear();
        if(CollectionsUtil.isNotEmpty(refIds)){
            refIds.clear();
        }

        if (contractArray.size()>0) {
            contractIds.addAll(JSONArray.parseArray(contractArray.toJSONString(),Long.class));
        }
        if(paymentArray.size()>0) {
            refIds.addAll(JSONArray.parseArray(paymentArray.toJSONString(),Long.class));
        }else if(paymentSheetArray.size()>0){
            refIds.addAll(JSONArray.parseArray(paymentSheetArray.toJSONString(),Long.class));
        }
    }



    private void getRefMapEliminateNoRef(JSONArray amountDetail,JSONObject data,Map<Long,String> contractMap,Integer paymentNum,Integer paymentSheetNum) throws XbbException{
        JSONArray refIdArray = data.getJSONArray(InvoiceEnum.CONTRACT_ID.getAttr());
        JSONArray refNoArray = data.getJSONArray(InvoiceEnum.CONTRACT_ID_LINK_TEXT.getAttr());
        Map<Long,List<Long>> refIdMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        String attr;
        if(paymentNum >0){
            attr = InvoiceEnum.PAYMENT_ID.getAttr();
        }else if(paymentSheetNum >0){
            attr = InvoiceEnum.PAYMENT_SHEET_ID.getAttr();
        }else {
            return;
        }
        if(CollectionsUtil.isNotEmpty(amountDetail)) {
            checkAmountDetailFormat(amountDetail);
            for (int i = 0; i < amountDetail.size(); i++) {
               JSONObject amountObject = amountDetail.getJSONObject(i);
               JSONObject jsonObject = null;
               if(Objects.nonNull(amountObject)){
                   jsonObject = amountObject.getJSONArray(attr).getJSONObject(0);
               }
               if(Objects.nonNull(jsonObject)) {
                   if (refIdMap.containsKey(jsonObject.getLong(InvoiceEnum.CONTRACT_ID.getSaasAttr()))) {
                        List<Long> idList = refIdMap.get(jsonObject.getLong(InvoiceEnum.CONTRACT_ID.getSaasAttr()));
                        idList.add(jsonObject.getLong(InvoiceEnum.CONTRACT_ID.getSaasAttr()));
                   }else {
                       List<Long> idList = new ArrayList<>();
                       idList.add(jsonObject.getLong(BasicConstant.ID));
                       if(jsonObject.containsKey(InvoiceEnum.CONTRACT_ID.getSaasAttr())){
                           refIdMap.put(jsonObject.getLong(InvoiceEnum.CONTRACT_ID.getSaasAttr()),idList);
                       }
                   }
               }
            }
           JSONArray contractIdArray = data.getJSONArray(InvoiceEnum.CONTRACT_ID.getAttr());
            if(CollectionsUtil.isNotEmpty(contractIdArray)) {
                for (int j = 0; j < contractIdArray.size(); j++) {
                    Long id = contractIdArray.getLong(j);
                    if (refIdMap.size() > 0) {
                        if (!refIdMap.containsKey(id)) {
                            refIdArray.remove(String.valueOf(id));
                            refNoArray.remove(contractMap.get(id));
                            contractMap.remove(id);
                        }
                    }
                }
            }
            data.put(InvoiceEnum.CONTRACT_ID.getAttr(),refIdArray);
            data.put(InvoiceEnum.CONTRACT_ID_LINK_TEXT.getAttr(),refNoArray);
        }
    }

    private void checkAmountDetailFormat(JSONArray amountDetail) throws XbbException{
        for (int i = 0; i < amountDetail.size(); i++) {
            JSONObject amountObject = amountDetail.getJSONObject(i);
            boolean errorFormat = amountObject.containsKey(InvoiceConstant.CONTRACT_ID) && amountObject.containsKey(InvoiceConstant.PAYMENT_ID) && amountObject.containsKey(InvoiceConstant.PAYMENT_SHEET_ID);
            if(errorFormat){
                throw new XbbException(InvoiceErrorCodeEnum.API_ERROR_216049);
            }
        }
    }

    /**
     * 获取关联id和关联的编号
     * @param isHasContract
     * @param isHasPayment
     * @param isHasPaymentSheet
     * @param contractMap
     * @param paymentMap
     * @param paymentSheetMap
     * @param data
     */
    private void getRefIdAndNoMap(boolean isHasContract,boolean isHasPayment,boolean isHasPaymentSheet,Map<Long,String> contractMap,Map<Long,String> paymentMap,Map<Long,String> paymentSheetMap,JSONObject data){
        if(isHasContract){
            commonGetRefEntity(InvoiceEnum.CONTRACT_ID.getAttr(),InvoiceEnum.CONTRACT_ID_LINK_TEXT.getAttr(),contractMap,data);
        }
        if(isHasPayment){
            commonGetRefEntity(InvoiceEnum.PAYMENT_ID.getAttr(),InvoiceEnum.PAYMENT_ID_LINK_TEXT.getAttr(),paymentMap,data);
        }
        if(isHasPaymentSheet){
            commonGetRefEntity(InvoiceEnum.PAYMENT_SHEET_ID.getAttr(),InvoiceEnum.PAYMENT_SHEET_ID_LINK_TEXT.getAttr(),paymentSheetMap,data);
        }
    }

    /**
     * 根据关联id 获取实体
     * @param idAttr id attr
     * @param noAttr 编号attr
     * @param map id 对应编号map
     *
     */
    private void commonGetRefEntity(String idAttr,String noAttr,Map<Long,String> map,JSONObject data){
        JSONArray refId = data.getJSONArray(idAttr);
        JSONArray refNo = data.getJSONArray(noAttr);
        for(int i=0;i < refId.size();i++){
            Long id = refId.getLong(i);
            String no = refNo.getString(i);
            map.put(id,no);
        }
    }




    /**
     * 检测关联关系可开金额为0的情况
     * @param data
     * @param isImport
     */
    private void checkRefNotInvoiceAmount(JSONObject data,Double totalMoney,Integer isImport) throws XbbException{
        if (Objects.equals(totalMoney, BasicConstant.ZERO_DOUBLE)) {
            if(Objects.equals(isImport,BasicConstant.ZERO)) {
                if (Objects.nonNull(data)) {
                    if (CollectionsUtil.isNotEmpty(data.getJSONArray(InvoiceEnum.CONTRACT_ID.getAttr()))) {
                        JSONArray contractArray = data.getJSONArray(InvoiceEnum.CONTRACT_ID.getAttr());
                        checkInvoice(contractArray, XbbRefTypeEnum.CONTRACT);
                    }
                    if (CollectionsUtil.isNotEmpty(data.getJSONArray(InvoiceEnum.PAYMENT_ID.getAttr()))) {
                        JSONArray contractArray = data.getJSONArray(InvoiceEnum.CONTRACT_ID.getAttr());
                        JSONArray paymentArray = data.getJSONArray(InvoiceEnum.PAYMENT_ID.getAttr());
                        checkInvoice(contractArray, XbbRefTypeEnum.CONTRACT);
                        checkInvoice(paymentArray, XbbRefTypeEnum.PAYMENT);
                    }
                    if (CollectionsUtil.isNotEmpty(data.getJSONArray(InvoiceEnum.PAYMENT_SHEET_ID.getAttr()))) {
                        JSONArray contractArray = data.getJSONArray(InvoiceEnum.CONTRACT_ID.getAttr());
                        JSONArray paymentSheetArray = data.getJSONArray(InvoiceEnum.PAYMENT_SHEET_ID.getAttr());
                        checkInvoice(contractArray, XbbRefTypeEnum.CONTRACT);
                        checkInvoice(paymentSheetArray, XbbRefTypeEnum.PAYMENT_SHEET);
                    }
                }
            }
        }
    }

    /**
     * 检测开票金额
     * @param refArray
     * @param xbbRefTypeEnum
     * @throws XbbException
     */
    private void checkInvoice(JSONArray refArray,XbbRefTypeEnum xbbRefTypeEnum) throws XbbException{
        String amountAttr = null;
        String invoiceAmountAttr = null;
        if(Objects.equals(xbbRefTypeEnum, XbbRefTypeEnum.CONTRACT)) {
          amountAttr = ContractEnum.AMOUNT.getAttr();
          invoiceAmountAttr = ContractEnum.INVOICE_AMOUNT.getAttr();
        }
        if(Objects.equals(xbbRefTypeEnum,XbbRefTypeEnum.PAYMENT)){
           amountAttr = PaymentEnum.AMOUNT.getAttr();
           invoiceAmountAttr = PaymentEnum.INVOICE_AMOUNT.getAttr();
        }else if(Objects.equals(xbbRefTypeEnum,XbbRefTypeEnum.PAYMENT_SHEET)){
           amountAttr = PaymentSheetEnum.AMOUNT.getAttr();
           invoiceAmountAttr = PaymentSheetEnum.INVOICE_AMOUNT.getAttr();
        }
        if(CollectionsUtil.isNotEmpty(refArray)) {
            for (int i = 0; i < refArray.size(); i++) {
                JSONObject jsonObject =  refArray.getJSONObject(i);
                if(jsonObject.containsKey(invoiceAmountAttr) && jsonObject.containsKey(amountAttr)) {
                    double amount = getDoubleOrDefaultFromFormData(jsonObject, amountAttr, 0D);
                    double invoiceAmount = getDoubleOrDefaultFromFormData(jsonObject,invoiceAmountAttr,0D);
                    if(Objects.equals(amount,invoiceAmount)){
                        throw new XbbException(InvoiceErrorCodeEnum.API_ERROR_216034);
                    }
                }
            }
        }
    }

    @Override
    public void formatExportValue(List<PaasFormDataEntityExt> paasFormDataESList, FormDataListDTO formDataListDTO, List<FieldAttrEntityForImport> fieldAttrList) {
        paasFormDataESList.forEach(item -> {
            JSONObject data = item.getData();
            Integer isRed = data.getInteger(InvoiceEnum.IS_RED.getAttr());
            Integer isCancel = data.getInteger(InvoiceEnum.IS_CANCEL.getAttr());
            if (Objects.equals(isRed, BasicConstant.ONE)) {
                data.put(InvoiceEnum.IS_RED.getAttr(), I18nMessageUtil.getMessage(CommonConstant.YES));
            } else {
                data.put(InvoiceEnum.IS_RED.getAttr(), "");
            }
            if (Objects.equals(isCancel, BasicConstant.ONE)) {
                data.put(InvoiceEnum.IS_CANCEL.getAttr(), I18nMessageUtil.getMessage(CommonConstant.YES));
            } else {
                data.put(InvoiceEnum.IS_CANCEL.getAttr(), "");
            }
        });
    }

    @Override
    public FormDataAddDTO formatExcelValue(ImportFormDataDTO importFormDataDTO, List<CellTitlePojo> titlePojoList, RowGroupPojo rowGroupPojo, List<FieldAttrEntityForImport> fieldAttrList) throws XbbException{
        FormDataAddDTO formDataAddDTO = new FormDataAddDTO();
        BeanUtil.copyProperties(importFormDataDTO, formDataAddDTO);
        formDataAddDTO.setSerialNo("");
        JSONObject dataJson = new JSONObject();
        List<List<CellValuePojo>> rowValueList = rowGroupPojo.getRowValueList();
        // 分组的第一条数据作为给实体对象赋值的数据
        List<CellValuePojo> cellValueList = rowValueList.get(0);

        Long linkCustomerId = 0L;
        List<PaasFormDataEntityExt> paasFormDataEntityExts = new ArrayList<>();
        List<Long> idList = new ArrayList<>();
        String paymentRelationship = null;
        for (FieldAttrEntityForImport fieldAttr : fieldAttrList) {
            String attr = fieldAttr.getAttr();
            String attrName = fieldAttr.getAttrName();
            Integer columnIndex = importHelper.getColumnIndexByTitle(titlePojoList, attrName, null);
            Object cellValue = importHelper.getValueByColumnIndex(cellValueList, columnIndex);
            if (Objects.isNull(cellValue) || StringUtil.isEmpty(cellValue.toString())) {
                continue;
            }
            if (Objects.equals(attr, InvoiceEnum.PAYMENT_RELATIONSHIP.getAttr())) {
                JSONObject jsonObject = new JSONObject();
                importHelper.formatDropDownValue4Import(jsonObject, fieldAttr, cellValue);
                paymentRelationship = jsonObject.getString(attr);
            }
        }
        for (FieldAttrEntityForImport fieldAttr : fieldAttrList) {
            String attr = fieldAttr.getAttr();
            Integer fieldType = fieldAttr.getFieldType();
            String attrName = fieldAttr.getAttrName();
            Integer columnIndex = importHelper.getColumnIndexByTitle(titlePojoList, attrName, null);
            Object cellValue = importHelper.getValueByColumnIndex(cellValueList, columnIndex);
            if (Objects.equals(attr, InvoiceEnum.CUSTOMER_NAME.getAttr())) {
                // 关联客户根据linkedType判断
                linkCustomerId = importHelper.formatLinkCustomer2CustomerId(titlePojoList, dataJson, rowValueList, fieldAttr);
            } else if (Objects.equals(fieldType, FieldTypeEnum.SUB_FORM.getType())) {
                importHelper.formatSubFormValue4Import(rowValueList, titlePojoList, importFormDataDTO, fieldAttr, dataJson);
            } else {
                if (Objects.isNull(cellValue) || StringUtil.isEmpty(cellValue.toString())) {
                    continue;
                }
                if (ImportHelper.commonHandleFieldType.contains(fieldAttr.getFieldType())) {
                    importHelper.formatCommonField(dataJson, fieldAttr, cellValue);
                } else {
                    if (Objects.equals(attr, InvoiceEnum.CONTRACT_ID.getAttr())) {
                        //去重
                        cellValue = importHelper.removeDuplicatesCellValue(cellValue);
                        paasFormDataEntityExts = importHelper.formatMultiRelyBusiness(linkCustomerId, dataJson, fieldAttr, cellValue, ContractEnum.LINK_CUSTOMER.getAttr());
                        if(CollectionsUtil.isNotEmpty(paasFormDataEntityExts)) {
                            paasFormDataEntityExts.forEach(item -> {
                                idList.add(item.getId());
                            });
                        }
                    } else if (Objects.equals(attr, InvoiceEnum.PAYMENT_ID.getAttr())) {
                        if(CollectionsUtil.isEmpty(paasFormDataEntityExts)){
                            throw new XbbException(InvoiceErrorCodeEnum.API_ERROR_216033);
                        }
                        if(Objects.equals(paymentRelationship,PaymentRelationshipEnum.PAYMENT_SHEET.getCode())){
                            throw new XbbException(InvoiceErrorCodeEnum.API_ERROR_216043);
                        }
                        //去重
                        cellValue = importHelper.removeDuplicatesCellValue(cellValue);
                        if(CollectionsUtil.isNotEmpty(paasFormDataEntityExts)) {
                            importHelper.formatInvoiceMultiRelyBusiness(idList, dataJson, fieldAttr, cellValue, PaymentEnum.CONTRACT.getAttr());
                        }
                    } else if(Objects.equals(attr,InvoiceEnum.PAYMENT_SHEET_ID.getAttr())){
                        if(CollectionsUtil.isEmpty(paasFormDataEntityExts)){
                            throw new XbbException(InvoiceErrorCodeEnum.API_ERROR_216033);
                        }
                        if(Objects.equals(paymentRelationship,PaymentRelationshipEnum.PAYMENT.getCode())){
                            throw new XbbException(InvoiceErrorCodeEnum.API_ERROR_216043);
                        }
                        //去重
                        cellValue = importHelper.removeDuplicatesCellValue(cellValue);
                        if(CollectionsUtil.isNotEmpty(paasFormDataEntityExts)) {
                            importHelper.formatInvoiceMultiRelyBusiness(idList, dataJson, fieldAttr, cellValue, PaymentSheetEnum.CONTRACT.getAttr());
                        }
                        if(CollectionsUtil.isNotEmpty(paasFormDataEntityExts)){
                            importHelper.checkInvoiceMultiRelyBusiness(idList,fieldAttr,cellValue,PaymentSheetEnum.CONTRACT.getAttr());
                        }
                    }else if (Objects.equals(fieldType, FieldTypeEnum.SERIALNO.getType())) {
                        formDataAddDTO.setSerialNo(cellValue.toString());
                    } else if (Objects.equals(fieldType, FieldTypeEnum.LINK_DATA.getType())) {
                        importHelper.formatLinkData(cellValue, fieldAttr, dataJson);
                    } else if (Objects.equals(fieldType, FieldTypeEnum.LINK_DATA_MULTI.getType())) {
                        importHelper.formatLinkDataMulti(cellValue, importFormDataDTO, fieldAttr, dataJson);
                    } else {
                        dataJson.put(attr, cellValue);
                    }
                }
            }
        }
        formDataAddDTO.setDataList(dataJson);
        return formDataAddDTO;
    }

    /**
     * 编辑 时 获取红冲金额
     * @param originId
     * @param corpid
     * @param editInvoiceId
     * @return
     * @throws XbbException
     */
    @Override
    public Double getRedTotalMoneyByEdit(Long originId, String corpid,Long editInvoiceId) throws XbbException {
        return saasInvoiceHelp.getRedTotalMoneyByEdit(originId, corpid, editInvoiceId);
    }
    /**
     * 根据关联id 获取红冲金额
     * @param originId
     * @param corpid
     * @return
     * @throws XbbException
     */
    @Override
    public Map<Long,Double> getRedTotalMoneyByRef(Long originId,String corpid,Long refId,XbbRefTypeEnum xbbRefTypeEnum) throws XbbException {
        Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<String, Object> map = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        param.put(ParameterConstant.CORPID, corpid);
        param.put(ParameterConstant.DEL, DelEnum.NORMAL.getDel());
        if(Objects.equals(xbbRefTypeEnum,XbbRefTypeEnum.CONTRACT)){
            param.put(InvoiceEnum.CONTRACT_ID.getAttr(),refId);
            map.put(InvoiceConstant.CONTRACT_ID,refId);
        }else if(Objects.equals(xbbRefTypeEnum,XbbRefTypeEnum.PAYMENT)){
            param.put(InvoiceEnum.PAYMENT_ID.getAttr(),refId);
            map.put(InvoiceConstant.PAYMENT_ID,refId);
        }else if(Objects.equals(xbbRefTypeEnum,XbbRefTypeEnum.PAYMENT_SHEET)){
            param.put(InvoiceEnum.PAYMENT_SHEET_ID.getAttr(),refId);
            map.put(InvoiceConstant.PAYMENT_SHEET_ID,refId);
        }
        List<PaasFormDataEntityExt> paasFormDataEntityExts = paasEsModel.selectByOneCondition(RedundantTemplateTypeEnum.INVOICE.getCode(), InvoiceEnum.ORIGIN_ID.getAttr(), originId, param, IndexTypeEnum.IDX_SAAS_INVOICE);
        List<Long> idIn = new ArrayList<>();
        paasFormDataEntityExts.forEach(paasFormDataEntityExt -> {
            idIn.add(paasFormDataEntityExt.getId());
        });
        map.put(ParameterConstant.CORPID, corpid);
        map.put(ParameterConstant.DEL, DelEnum.NORMAL.getDel());
        map.put("invoiceIdIn",idIn);
        map.put("type",-1);
        List<InvoiceRelationshipEntity> invoiceRelationshipEntityList = invoiceRelationshipModel.getByParam(map);
        Map<Long,Double> redMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Double redTotalMoney = 0D;
        for (InvoiceRelationshipEntity invoiceRelationshipEntity : invoiceRelationshipEntityList) {
            Double money = invoiceRelationshipEntity.getMoney();
            if(Objects.equals(xbbRefTypeEnum,XbbRefTypeEnum.CONTRACT)){
                if(redMap.containsKey(invoiceRelationshipEntity.getContractId())) {
                    money = redMap.get(invoiceRelationshipEntity.getContractId()) + money;
                    redMap.put(invoiceRelationshipEntity.getContractId(), money);
                }else {
                    redMap.put(invoiceRelationshipEntity.getContractId(), money);
                }
            }else if(Objects.equals(xbbRefTypeEnum,XbbRefTypeEnum.PAYMENT)){
                if(redMap.containsKey(invoiceRelationshipEntity.getPaymentId())) {
                    money = redMap.get(invoiceRelationshipEntity.getPaymentId()) + money;
                    redMap.put(invoiceRelationshipEntity.getPaymentId(), money);
                }else {
                    redMap.put(invoiceRelationshipEntity.getPaymentId(), money);
                }
            }else if(Objects.equals(xbbRefTypeEnum,XbbRefTypeEnum.PAYMENT_SHEET)){
                if(redMap.containsKey(invoiceRelationshipEntity.getPaymentSheetId())) {
                    money = redMap.get(invoiceRelationshipEntity.getPaymentSheetId()) + money;
                    redMap.put(invoiceRelationshipEntity.getPaymentSheetId(), money);
                }else {
                    redMap.put(invoiceRelationshipEntity.getPaymentSheetId(), money);
                }
            }
        }
        return redMap;
    }

    /**
     * 获取红冲总金额
     *
     * @param originIdIn 原始id
     * @param corpid   公司id
     * @return double
     * @throws XbbException 异常
     */
    @Override
    public Map<Long, Double> getRedTotalMoneyByIdIn(List<Long> originIdIn,List<Long> negIdIn, String corpid) throws XbbException {
        return saasInvoiceHelp.getRedTotalMoneyByIdIn(originIdIn, negIdIn, corpid);
    }

    @Override
    public Map<Long,Long> getInvoiceRedIdMappingByIdIn(List<Long> originIdIn, String corpid) throws XbbException {
        List<String> dataIdStrList = JSONArray.parseArray(JSONArray.toJSONString(originIdIn),String.class);
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        boolQueryBuilder.filter(termsQuery(StringConstant.JSON_DATA + StringConstant.POINT + InvoiceEnum.ORIGIN_ID.getAttr(), dataIdStrList));
        boolQueryBuilder.filter(termQuery(StringConstant.CORPID + StringConstant.POINT + StringConstant.KEY_WORD , corpid));
        boolQueryBuilder.filter(termQuery(ParameterConstant.DEL, DelEnum.NORMAL.getDel()));
        List<String> fieldList = new ArrayList<>();
        fieldList.add(BasicConstant.ID);
        fieldList.add(InvoiceEnum.getAttrConnectData(InvoiceEnum.ORIGIN_ID));
        List<PaasFormDataEntityExt> originInvoiceList = esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_INVOICE, boolQueryBuilder, PaasFormDataEntityExt.class, fieldList);
        Map<Long,Long> idMapping = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Long id;
        Long originId;
        for (PaasFormDataEntityExt paasFormDataEntityExt : originInvoiceList) {
            id = paasFormDataEntityExt.getId();
            originId = FastJsonHelper.getLongOrDefaultFromFormData(paasFormDataEntityExt.getData(), InvoiceEnum.ORIGIN_ID.getAttr(), 0L);
            idMapping.put(id, originId);
        }
        return idMapping;
    }

    @Override
    public ComputeInvoiceAmountVO getComputeInvoiceAmount(ComputeInvoiceAmountDTO computeInvoiceAmountDTO){
        double count = 0D;
        List<PaasFormDataEntityExt> contractList = computeInvoiceAmountDTO.getContractList();
        List<PaasFormDataEntityExt> paymentList = computeInvoiceAmountDTO.getPaymentList();

        //如果没有选择关联回款
        if(CollectionsUtil.isNotEmpty(paymentList)){
            if(contractList.size()>BasicConstant.ONE) {
                for (PaasFormDataEntityExt contractEntityExts : contractList) {
                    JSONObject jsonObject = contractEntityExts.getData();
                    double contractAmount = jsonObject.getDouble(ContractEnum.AMOUNT.getAttr());
                    count = MoneyUtil.formatDouble(count+contractAmount,2);
                }
            }else if(BasicConstant.ONE.equals(contractList.size())) {
                   JSONObject jsonObject = contractList.get(0).getData();
                   count = jsonObject.getDouble(ContractEnum.UN_INVOICE_AMOUNT.getAttr());
            }
        }else {
            //如果选择了关联回款
            if(paymentList.size()>BasicConstant.ONE){
                for (PaasFormDataEntityExt paymentEntityExts : paymentList){
                    JSONObject jsonObject = paymentEntityExts.getData();
                    Double amount = jsonObject.getDouble(PaymentEnum.AMOUNT.getAttr());
                    count = MoneyUtil.formatDouble(count+amount,2);
                }
            }else if(BasicConstant.ONE.equals(paymentList.size())){
                JSONObject jsonObject = paymentList.get(0).getData();
                Double planAmount = jsonObject.getDouble(PaymentEnum.AMOUNT.getAttr());
                Double uninvoiceAmount = jsonObject.getDouble(PaymentEnum.INVOICE_AMOUNT.getAttr());
                count = MoneyUtil.formatDouble(planAmount-uninvoiceAmount,2);
            }
        }
        ComputeInvoiceAmountVO computeInvoiceAmountVO = new ComputeInvoiceAmountVO();
        computeInvoiceAmountVO.setCount(count);
        return computeInvoiceAmountVO;
    }

    /**
     * 审批、新建、编辑、还原 金额判断
     *
     * @param corpid       公司id
     * @param invoiceId    发票id
     * @param invoiceMoney 合同或回款的 开票金额
     * @param relationIdIn 合同或回款的id（新增或编辑）
     * @author yuqian
     * 单次合同开票判断开票金额小于合同可开;
     * 单次回款开票判断开票金额小于合同可开和回款可开;
     * 回款 合同开票金额小于合同可开金额,开票金额小于应收款可开金额
     */
    @Override
    @SuppressWarnings("unchecked")
    public void invoiceAmountJudgment(String corpid, Long invoiceId, Double invoiceMoney, Map<String, Object> relationIdIn,Integer isImport,Integer isCover,Integer isRestore,JSONArray amountDetail) throws XbbException {
        saasInvoiceHelp.invoiceAmountJudgment(corpid, invoiceId, invoiceMoney, relationIdIn, isImport, isCover, isRestore, amountDetail);
    }





    /**
     * 获取发票信息和寄送信息
     *
     * @param customerInvoiceAndExpressGetDTO 入参
     * @return 回参
     * @throws XbbException 异常
     */
    @Override
    public CustomerInvoiceAndExpressGetVO getCustomerInvoiceAndExpress(CustomerInvoiceAndExpressGetDTO customerInvoiceAndExpressGetDTO) throws XbbException {
        CustomerInvoiceAndExpressGetVO customerInvoiceAndExpressGetVO = new CustomerInvoiceAndExpressGetVO();
        Long customerId = customerInvoiceAndExpressGetDTO.getCustomerId();
        Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        param.put(ParameterConstant.CORPID, customerInvoiceAndExpressGetDTO.getCorpid());
        param.put(ParameterConstant.DEL, DelEnum.NORMAL.getDel());
        param.put("customerId", customerId);
        param.put("orderByStr", "is_default desc");
        List<CustomerInvoiceEntity> customerInvoiceEntityList = customerInvoiceModel.findEntitys(param);
        JSONArray subForm_1 = new JSONArray();
        if (!customerInvoiceEntityList.isEmpty()) {
            for (CustomerInvoiceEntity customerInvoiceEntity : customerInvoiceEntityList) {
                // 前端需要的参数
                JSONObject subObj1 = new JSONObject();
                //subObj1.put(CustomerInvoiceEnum.CUSTOMER_INVOICE_ID.getAttr(), customerInvoiceEntity.getId()
                JSONObject titleObj = new JSONObject();
                titleObj.put("text", customerInvoiceEntity.getTitleTypeStr());
                titleObj.put(StringConstant.VALUE, customerInvoiceEntity.getTitleType());
                subObj1.put(CustomerInvoiceEnum.TITLE_TYPE.getAttr(),titleObj);
                subObj1.put(CustomerInvoiceEnum.TITLE.getAttr(), customerInvoiceEntity.getTitle());
                subObj1.put(CustomerInvoiceEnum.TAXPAYER_NO.getAttr(), customerInvoiceEntity.getTaxpayerNo());
                subObj1.put(CustomerInvoiceEnum.REGISTERED_PHONE.getAttr(), customerInvoiceEntity.getRegisteredPhone());
                subObj1.put(CustomerInvoiceEnum.INVOICE_ADDRESS.getAttr(), customerInvoiceEntity.getInvoiceAddress());
                subObj1.put(CustomerInvoiceEnum.BANK.getAttr(), customerInvoiceEntity.getBank());
                subObj1.put(CustomerInvoiceEnum.ACCOUNT.getAttr(), customerInvoiceEntity.getAccount());
                subForm_1.add(subObj1);
            }
        }
        JSONArray subForm_2 = new JSONArray();
        param.put("orderByStr", "is_default desc");
        List<CustomerExpressEntity> customerExpressEntityList = customerExpressModel.findEntitys(param);
        if (!customerExpressEntityList.isEmpty()) {
            // 前端需要的参数
            for (CustomerExpressEntity customerExpressEntity : customerExpressEntityList) {
                JSONObject subObj2 = new JSONObject();
               // subObj2.put(CustomerExpressEnum.CUSTOMER_EXPRESS_ID.getAttr(), customerExpressEntity.getId());
                subObj2.put(CustomerExpressEnum.NAME.getAttr(), customerExpressEntity.getName());
                subObj2.put(CustomerExpressEnum.CONTACT.getAttr(), customerExpressEntity.getContact());
                subObj2.put(CustomerExpressEnum.PHONE.getAttr(), customerExpressEntity.getPhone());
                subObj2.put(CustomerExpressEnum.ZIP_CODE.getAttr(), customerExpressEntity.getZipCode());
                JSONObject addressObj = new JSONObject();
                addressObj.put("address", customerExpressEntity.getAddress());
                addressObj.put("city", customerExpressEntity.getCity());
                addressObj.put("district", customerExpressEntity.getDistrict());
                addressObj.put("province", customerExpressEntity.getProvince());
                subObj2.put(CustomerExpressEnum.ADDRESS.getAttr(), addressObj);
                subForm_2.add(subObj2);
            }
        }
        customerInvoiceAndExpressGetVO.setSubForm_1(subForm_1);
        customerInvoiceAndExpressGetVO.setSubForm_2(subForm_2);
        return  customerInvoiceAndExpressGetVO;
    }

    @Override
    public InvoiceDeleteBatchVO deleteBatch(InvoiceDeleteBatchDTO invoiceDeleteBatchDTO, DelEnum delEnum) throws XbbException {
        InvoiceDeleteBatchVO invoiceDeleteBatchVO = new InvoiceDeleteBatchVO();
        String corpid = invoiceDeleteBatchDTO.getCorpid();
        List<Long> errorDataId = new ArrayList<>();
        List<String> errorDataNo = new ArrayList<>();
        Set<String> errorTypeSet = new HashSet<>();
        List<PaasFormDataEntityExt> paasFormDataEntityExts = null;
        Set<Long> contractIdSet = new HashSet<>();
        Set<Long> planIdSet = new HashSet<>();
        Set<Long> sheetIdSet = new HashSet<>();
        try {
            // TODO 删除权限校验
            // 批量删除发票
            List<Long> idIn = invoiceDeleteBatchDTO.getDataIdList();
            Map<String, Object> param = BeanUtil.convertBean2Map(invoiceDeleteBatchDTO, true);
            param.put("idIn", idIn);
            param.put(ParameterConstant.DEL, DelEnum.NORMAL.getDel());
            Map<Long,String> redNoMapping = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            Map<Long, Double> redMoneyMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            Map<Long,Long> deletRedMapping = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            List<InvoiceEntityExt> invoiceList = invoiceModel.findEntitys(param);

            List<PaasFormDataEntityExt> paasFormDataExts = new ArrayList<>(invoiceList.size());
            BeanUtil.copyPropertiesList(invoiceList, paasFormDataExts, PaasFormDataEntityExt.class);

            if(CollectionsUtil.isNotEmpty(invoiceList)) {
                for(InvoiceEntityExt invoiceEntityExt : invoiceList){
                    JSONObject data = invoiceEntityExt.getData();
                    if(Objects.nonNull(data)) {
                        if(FastJsonHelper.getLongOrDefaultFromFormData(data, InvoiceEnum.ORIGIN_ID.getAttr(), 0L) > 0) {
                            redNoMapping.put(invoiceEntityExt.getId(),invoiceEntityExt.getSerialNo());
                            redMoneyMap.put(invoiceEntityExt.getId(),getDoubleOrDefaultFromFormData(data,InvoiceEnum.TOTAL_MONEY.getAttr(),0D));
                            deletRedMapping.put(invoiceEntityExt.getId(),FastJsonHelper.getLongOrDefaultFromFormData(data,InvoiceEnum.ORIGIN_ID.getAttr(),0L));
                        }
                }
            }
            }
            //在这一步 根据要删掉的发票id去红冲发票对应原发票的mapping中 找原发票id,若删除的发票中有原单发票,即可忽略掉红冲发票
            List<Long> removeRedIds = new ArrayList<>();
            idIn.forEach(item -> {
                Long originId = deletRedMapping.get(item);
                if(idIn.contains(originId)){
                    //既包含红冲也包含原单
                    removeRedIds.add(item);
                }
            });
            if(CollectionsUtil.isNotEmpty(idIn) && CollectionsUtil.isNotEmpty(removeRedIds)) {
                idIn.removeAll(removeRedIds);
            }
            if (invoiceList.size() <= 0) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100404, SystemErrorCodeEnum.API_ERROR_100404.getMsg());
            }
            List<Long> redIdIn = new ArrayList<>();
            // 删除原发票关联红冲发票
            List<String> idInString = new ArrayList<>();
            idIn.forEach((id)-> idInString.add(id.toString()));
            //资金管理的新销项发票需要查金额明细才能计算删除红冲时是否会超过为开票的值
            Map<String,Object> queryMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            queryMap.put("del",BasicConstant.ZERO);
            queryMap.put("invoiceIdIn",idIn);
            queryMap.put("isCancel",BasicConstant.ZERO);
            queryMap.put("corpid",corpid);
            queryMap.put("type",-1);
            List<InvoiceRelationshipEntity> invoiceRelatEntities = invoiceRelationshipModel.findEntitys(queryMap);
            //查一遍所有红冲发票然后根据原发票id 对应红冲发票id
            //这一步就是查询正常发票的红冲发票，删除正常发票连带他的红冲发票也会删除，如果删除的是红冲发票这一部查询不到什么。
            String esData = StringConstant.JSON_DATA + StringConstant.POINT;
            BoolQueryBuilder boolQueryBuilder = boolQuery();
            boolQueryBuilder.filter(termsQuery(esData + InvoiceEnum.ORIGIN_ID.getAttr(), idInString));
            boolQueryBuilder.filter(termQuery(StringConstant.CORPID + StringConstant.POINT + StringConstant.KEY_WORD , corpid));
            List<String> fieldList = new ArrayList<>();
            fieldList.add(StringConstant.DATA_ID);
            fieldList.add(InvoiceEnum.SHEET_NO.getAttr());
            fieldList.add(esData + InvoiceEnum.TOTAL_MONEY.getAttr());
            fieldList.add(esData + InvoiceEnum.ORIGIN_ID.getAttr());
            List<PaasFormDataEntityExt> originInvoiceList = esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_INVOICE, boolQueryBuilder, PaasFormDataEntityExt.class, fieldList);
            if (Objects.isNull(originInvoiceList)) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
            }
            Map<Long,Long> idMapping = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            if(!originInvoiceList.isEmpty()) {
                originInvoiceList.forEach((item) -> {
                    //红冲id
                    redIdIn.add(item.getDataId());
                    idMapping.put(item.getDataId(), item.getData().getLong(InvoiceEnum.ORIGIN_ID.getAttr()));
                });
            }

            //资金管理第一期和之前的版本比起来,加了金额明细,老的数据没有金额明细,合并开票规则和新版本不同
            Set<Long> newEditionIdSet = new HashSet<>();
            //新数据的红冲明细
            Map<Long,Map<Long,Double>> refContractRedInvoiceMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            Map<Long,Map<Long,Double>> refPaymentRedInvoiceMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            Map<Long,Map<Long,Double>> refPaymentSheetRedInvoiceMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            invoiceRelatEntities.forEach(item ->{
                if(item.getContractId()>0){
                    Map<Long,Double> map = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                    if(refContractRedInvoiceMap.containsKey(item.getInvoiceId())){
                        map = refContractRedInvoiceMap.getOrDefault(item.getInvoiceId(),new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY));
                    }
                    saasSaveHelp.addMapNormal(map,item.getContractId(),item.getMoney());
                    if(!refContractRedInvoiceMap.containsKey(item.getInvoiceId())){
                        refContractRedInvoiceMap.put(item.getInvoiceId(),map);
                    }
                }
                if(item.getPaymentId()>0){
                    Map<Long,Double> map = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                    if(refPaymentRedInvoiceMap.containsKey(item.getInvoiceId())){
                        map = refPaymentRedInvoiceMap.getOrDefault(item.getInvoiceId(),new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY));
                    }
                    saasSaveHelp.addMapNormal(map,item.getPaymentId(),item.getMoney());
                    if(!refPaymentRedInvoiceMap.containsKey(item.getInvoiceId())){
                        refPaymentRedInvoiceMap.put(item.getInvoiceId(),map);
                    }
                }
                if(item.getPaymentSheetId()>0){
                    Map<Long,Double> map = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                    if(refPaymentSheetRedInvoiceMap.containsKey(item.getInvoiceId())){
                        map = refPaymentSheetRedInvoiceMap.getOrDefault(item.getInvoiceId(),new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY));
                    }
                    saasSaveHelp.addMapNormal(map,item.getPaymentSheetId(),item.getMoney());
                    if(!refPaymentSheetRedInvoiceMap.containsKey(item.getInvoiceId())){
                        refPaymentSheetRedInvoiceMap.put(item.getInvoiceId(),map);
                    }
                }

                newEditionIdSet.add(item.getInvoiceId());
            });
            Set<Long> newPaymnetIdSet = new HashSet<>();
            Set<Long> newPaymentSheetIdSet = new HashSet<>();
            Set<Long> newContractIdSet = new HashSet<>();
            Set<Long> oldPaymnetIdSet = new HashSet<>();
            Set<Long> oldPaymentSheetIdSet = new HashSet<>();
            Set<Long> oldContractIdSet = new HashSet<>();
            //旧版本数据
            Set<Long> oldEditionIdSet = new HashSet<>();
            Map<Long,Double> contractAmountMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            Map<Long,Double> paymentAmountMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            Map<Long,Double> paymentSheetAmountMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            if(CollectionsUtil.isNotEmpty(invoiceList)) {
                for (InvoiceEntityExt invoiceEntityExt : invoiceList) {
                    boolean oldDataFlag = false;
                    Long id = invoiceEntityExt.getId();
                    if(!newEditionIdSet.contains(id)){
                        oldEditionIdSet.add(id);
                        oldDataFlag = true;
                    }
                    JSONObject data = invoiceEntityExt.getData();
                    if(Objects.nonNull(data)){
                        int isRed = getIntegerOrDefaultFromFormData(data,InvoiceEnum.IS_RED.getAttr(),BasicConstant.ZERO);
                        if(Objects.equals(isRed,BasicConstant.ONE)){
                            if(Objects.nonNull(data.getJSONArray(InvoiceEnum.PAYMENT_ID.getAttr()))){
                                //根据关联的关系去查
                               List<Long> idList = JSONArray.parseArray(data.getJSONArray(InvoiceEnum.PAYMENT_ID.getAttr()).toJSONString(),Long.class);
                               if(oldDataFlag){
                                   oldPaymnetIdSet.addAll(idList);
                               }else {
                                   newPaymnetIdSet.addAll(idList);
                               }
                            }
                            if(Objects.nonNull(data.getJSONArray(InvoiceEnum.PAYMENT_SHEET_ID.getAttr()))){
                                List<Long> idList = JSONArray.parseArray(data.getJSONArray(InvoiceEnum.PAYMENT_SHEET_ID.getAttr()).toJSONString(),Long.class);
                                if(oldDataFlag){
                                    oldPaymentSheetIdSet.addAll(idList);
                                }else {
                                    newPaymentSheetIdSet.addAll(idList);
                                }
                            }
                            if(Objects.nonNull(data.getJSONArray(InvoiceEnum.CONTRACT_ID.getAttr()))){
                                List<Long> idList = JSONArray.parseArray(data.getJSONArray(InvoiceEnum.CONTRACT_ID.getAttr()).toJSONString(),Long.class);
                                if(oldDataFlag){
                                    oldContractIdSet.addAll(idList);
                                }else {
                                    newContractIdSet.addAll(idList);
                                }
                            }
                        }
                    }
                }
                queryMap.remove("type");
                //都是有红冲的关联数据
                Map<Long,Double> paymentInvoiceHistoryMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                Map<Long,Double> paymentSheetInvoiceHistoryMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                Map<Long,Double> contractInvoiceHistoryMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                Map<Long,List<Long>> invoiceRefContractMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                Map<Long,List<Long>> invoiceRefPaymentMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                Map<Long,List<Long>> invoiceRefPaymentSheetMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                //新数据的关联关系查询
                getInvoiceAmountByRelationship(newPaymnetIdSet,queryMap,paymentInvoiceHistoryMap,paymentAmountMap,invoiceRefContractMap,invoiceRefPaymentMap,invoiceRefPaymentSheetMap,InvoiceConstant.PAYMENT_ID_IN,corpid,XbbRefTypeEnum.PAYMENT);
                getInvoiceAmountByRelationship(newPaymentSheetIdSet,queryMap,paymentSheetInvoiceHistoryMap,paymentSheetAmountMap,invoiceRefContractMap,invoiceRefPaymentMap,invoiceRefPaymentSheetMap,InvoiceConstant.PAYMENT_SHEET_ID_IN,corpid,XbbRefTypeEnum.PAYMENT_SHEET);
                getInvoiceAmountByRelationship(newContractIdSet,queryMap,contractInvoiceHistoryMap,contractAmountMap,invoiceRefContractMap,invoiceRefPaymentMap,invoiceRefPaymentSheetMap,InvoiceConstant.CONTRACT_ID_IN,corpid,XbbRefTypeEnum.CONTRACT);
                //老数据直接查明细表,只能查到开票数据,无法查到红冲数据
                getInvoiceAmountByRelationship(oldPaymnetIdSet,queryMap,paymentInvoiceHistoryMap,paymentAmountMap,invoiceRefContractMap,invoiceRefPaymentMap,invoiceRefPaymentSheetMap,InvoiceConstant.PAYMENT_ID_IN,corpid,XbbRefTypeEnum.PAYMENT);
                getInvoiceAmountByRelationship(oldPaymentSheetIdSet,queryMap,paymentSheetInvoiceHistoryMap,paymentSheetAmountMap,invoiceRefContractMap,invoiceRefPaymentMap,invoiceRefPaymentSheetMap,InvoiceConstant.PAYMENT_SHEET_ID_IN,corpid,XbbRefTypeEnum.PAYMENT_SHEET);
                getInvoiceAmountByRelationship(oldContractIdSet,queryMap,contractInvoiceHistoryMap,contractAmountMap,invoiceRefContractMap,invoiceRefPaymentMap,invoiceRefPaymentSheetMap,InvoiceConstant.CONTRACT_ID_IN,corpid,XbbRefTypeEnum.CONTRACT);
                //老数据的红冲数据只能去查发票表
                BoolQueryBuilder boolQuery = boolQuery();
                boolQuery.filter(termsQuery(esData + InvoiceEnum.PAYMENT_ID.getAttr(),new ArrayList<>(oldPaymnetIdSet)));
                boolQuery.filter(termQuery(StringConstant.CORPID + StringConstant.POINT + StringConstant.KEY_WORD , corpid));
                boolQuery.filter(termQuery(esData + InvoiceEnum.IS_RED.getAttr(),BasicConstant.ONE));
                boolQuery.filter(termQuery(StringConstant.DEL, DelEnum.NORMAL.getDel()));
                fieldList = new ArrayList<>();
                fieldList.add(StringConstant.DATA_ID);
                fieldList.add(esData + InvoiceEnum.TOTAL_MONEY.getAttr());
                fieldList.add(esData + InvoiceEnum.CONTRACT_ID.getAttr());
                fieldList.add(esData + InvoiceEnum.PAYMENT_ID.getAttr());
                fieldList.add(esData + InvoiceEnum.PAYMENT_SHEET_ID.getAttr());
                fieldList.add(esData + InvoiceEnum.ORIGIN_ID.getAttr());
                List<PaasFormDataEntityExt> oldRedPaymentList = esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_INVOICE, boolQueryBuilder, PaasFormDataEntityExt.class,fieldList);
                saasSaveHelp.getRefAmountByEsList(oldRedPaymentList,paymentInvoiceHistoryMap,paymentAmountMap,XbbRefTypeEnum.PAYMENT);
                BoolQueryBuilder boolQueryBuilder1 = boolQuery();
                boolQueryBuilder1.filter(termsQuery(esData + InvoiceEnum.PAYMENT_SHEET_ID.getAttr(),new ArrayList<>(oldPaymentSheetIdSet)));
                boolQueryBuilder1.filter(termQuery(StringConstant.CORPID + StringConstant.POINT + StringConstant.KEY_WORD , corpid));
                boolQueryBuilder1.filter(termQuery(esData + InvoiceEnum.IS_RED.getAttr(),BasicConstant.ONE));
                boolQueryBuilder1.filter(termQuery(StringConstant.DEL, DelEnum.NORMAL.getDel()));
                List<PaasFormDataEntityExt> oldRedPaymentSheetList = esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_INVOICE, boolQueryBuilder, PaasFormDataEntityExt.class,fieldList);
                saasSaveHelp.getRefAmountByEsList(oldRedPaymentSheetList,paymentSheetInvoiceHistoryMap,paymentSheetAmountMap,XbbRefTypeEnum.PAYMENT_SHEET);
                BoolQueryBuilder boolQueryBuilder2 = boolQuery();
                boolQueryBuilder2.filter(termsQuery(esData + InvoiceEnum.CONTRACT_ID.getAttr(),new ArrayList<>(oldContractIdSet)));
                boolQueryBuilder2.filter(termQuery(StringConstant.CORPID + StringConstant.POINT + StringConstant.KEY_WORD , corpid));
                boolQueryBuilder2.filter(termQuery(esData + InvoiceEnum.IS_RED.getAttr(),BasicConstant.ONE));
                boolQueryBuilder2.filter(termQuery(StringConstant.DEL, DelEnum.NORMAL.getDel()));
                List<PaasFormDataEntityExt> oldRedContractList = esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_INVOICE, boolQueryBuilder, PaasFormDataEntityExt.class,fieldList);
                saasSaveHelp.getRefAmountByEsList(oldRedContractList,contractInvoiceHistoryMap,contractAmountMap,XbbRefTypeEnum.CONTRACT);
                CheckRedInvoiceDeletePojo checkRedInvoiceDeletePojo = new CheckRedInvoiceDeletePojo(invoiceRefContractMap,invoiceRefPaymentMap,invoiceRefPaymentSheetMap,contractAmountMap,paymentAmountMap,paymentSheetAmountMap,contractInvoiceHistoryMap,paymentInvoiceHistoryMap,paymentSheetInvoiceHistoryMap,refContractRedInvoiceMap,refPaymentRedInvoiceMap,refPaymentSheetRedInvoiceMap);
                checkRedInvoiceDelete(checkRedInvoiceDeletePojo,newEditionIdSet,redNoMapping,errorDataId,errorDataNo,errorTypeSet);
                checkRedInvoiceDelete(checkRedInvoiceDeletePojo,oldEditionIdSet,redNoMapping,errorDataId,errorDataNo,errorTypeSet);
                paasFormDataEntityExts = receivablesHelper.checkReceivablesWhetherCanDel(invoiceDeleteBatchDTO.getDataIdList(),invoiceDeleteBatchDTO.getCorpid(),errorDataId,errorDataNo,errorTypeSet, ModelTypeEnum.INVOICE.getXbbRefTypeEnum().getCode());
            }
            if(CollectionsUtil.isNotEmpty(errorDataId)){
                //去重
                Set<Long> errorDataIdSet = new HashSet<>(errorDataId);
                Set<String> errorDataNoSet = new HashSet<>(errorDataNo);
                errorDataId.clear();
                errorDataNo.clear();
                errorDataId.addAll(errorDataIdSet);
                errorDataNo.addAll(errorDataNoSet);
                idIn.removeAll(errorDataId);
                List<String> typeList = new ArrayList<>();
                //errorTypeSet.add(I18nMessageUtil.getMessage(ErrorMessageConstant.REF_INVOICE_AMOUNT_NOT_ENOUGH));
                typeList.addAll(errorTypeSet);
                invoiceDeleteBatchVO.setErrorDataList(errorDataNo);
                invoiceDeleteBatchVO.setErrorTypeList(typeList);
                invoiceDeleteBatchVO.setErrorDataMemo(SaasDeleteHelp.getErrorDataMemo(typeList, errorDataNo));
                List<InvoiceEntityExt> removeList = new ArrayList<>();
                for (InvoiceEntityExt invoiceEntityExt : invoiceList) {
                    for(Long id : errorDataId){
                        if(Objects.equals(invoiceEntityExt.getId(),id)){
                            removeList.add(invoiceEntityExt);
                        }
                    }
                }
                if(CollectionsUtil.isNotEmpty(invoiceList) && CollectionsUtil.isNotEmpty(removeList)) {
                    invoiceList.removeAll(removeList);
                }
            }
            if(!redIdIn.isEmpty()) {
                if(BasicConstant.ONE.equals(invoiceDeleteBatchDTO.getSingleFlag()) && BasicConstant.ONE.equals(redIdIn.size())){
                        invoiceModel.deleteByKeyAppointDel(redIdIn.get(0),corpid, delEnum);
                    }else {
                        invoiceModel.deleteBatch(redIdIn, corpid, delEnum.getDel());
                }
            }
            //查询编号
            List<String> no= new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            BoolQueryBuilder builder = boolQuery();
            // 添加corpid,formId,del
            builder.filter(termQuery("corpid.keyword", corpid));
            builder.filter(termQuery(StringConstant.DEL, DelEnum.NORMAL.getDel()));
            builder.filter(termsQuery(StringConstant.DATA_ID, idIn));
            List<String> noFieldList = new ArrayList<>();
            noFieldList.add(FieldTypeEnum.SERIALNO.getAlias());
            List<PaasFormDataEntityExt> noList = esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_INVOICE, builder, PaasFormDataEntityExt.class, noFieldList);
            for(PaasFormDataEntityExt entityExt : noList){
                String sheetNo = entityExt.getSerialNo();
                no.add(sheetNo);
            }
            if(!idIn.isEmpty()) {
                if(BasicConstant.ONE.equals(invoiceDeleteBatchDTO.getSingleFlag())
                        && BasicConstant.ONE.equals(idIn.size())){
                    invoiceModel.deleteByKeyAppointDel(idIn.get(0),corpid, delEnum);
                }else {
                    invoiceModel.deleteBatch(idIn, corpid, delEnum.getDel());
                }
                invoiceDeleteBatchVO.setDeleteIds(idIn);
            }
            // 删除红冲发票时更新原发票hasRed字段
            List<Long> hasOriginIdList = new ArrayList<>();
            for (InvoiceEntityExt invoiceEntityExt : invoiceList) {
                Long hasOriginId = FastJsonHelper.getLongFromFormData(invoiceEntityExt.getData(), InvoiceEnum.ORIGIN_ID.getAttr());
                if (Objects.nonNull(hasOriginId) && !Objects.equals(hasOriginId, 0L)) {
                    hasOriginIdList.add(hasOriginId);
                }
            }
            if (!hasOriginIdList.isEmpty()) {
                //红冲有多次红冲的情况,根据原始发票id 获取不是这次删除的发票
                Map<Long, Double> redTotalMoneyByIdIn = getRedTotalMoneyByIdIn(hasOriginIdList, idIn,corpid);
                for (Map.Entry<Long, Double> entry : redTotalMoneyByIdIn.entrySet()) {
                    hasOriginIdList.remove(entry.getKey());
                }
                if (!hasOriginIdList.isEmpty()) {
                    proUpdateHelp.updateByIds(XbbRefTypeEnum.INVOICE.getCode(), corpid, hasOriginIdList, InvoiceEnum.HAS_RED.getAttr(), 0);
                }
            }
            Map<String, Object> map = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            //查询所有发票明细 包括老数据
            List<Long> invoiceIdIn = invoiceDeleteBatchDTO.getDataIdList();
            map.put("invoiceIdIn", invoiceIdIn);
            map.put(ParameterConstant.CORPID, invoiceDeleteBatchDTO.getCorpid());
            map.put(ParameterConstant.DEL, DelEnum.NORMAL.getDel());
            List<InvoiceRelationshipEntity> invoiceRelationshipEntityList = invoiceRelationshipModel.findEntitys(map);
            Set<Long> redInvoiceSet = idMapping.keySet();
            List<Long> ids = new ArrayList<>(redInvoiceSet);
            //上面已经做了同时删除原发票和红冲发票时，去掉红冲，原发票查明细会算上红冲
            //ids.removeAll(invoiceIdIn);
            map.put("invoiceIdIn",ids);
            map.put("type",-1);
            List<InvoiceRelationshipEntity> redInvoiceRelationshipList = invoiceRelationshipModel.getByParam(map);
            invoiceRelationshipEntityList.addAll(redInvoiceRelationshipList);
            //这里做一次老数据的兼容
            BoolQueryBuilder boolQuery = boolQuery();
            boolQueryBuilder.filter(termsQuery(esData + InvoiceEnum.ORIGIN_ID.getAttr(),new ArrayList<>(oldEditionIdSet)));
            boolQueryBuilder.filter(termQuery(StringConstant.CORPID + StringConstant.POINT + StringConstant.KEY_WORD , corpid));
            boolQuery.filter(termQuery(esData + InvoiceEnum.IS_RED.getAttr(),BasicConstant.ONE));
            boolQuery.filter(termQuery(StringConstant.DEL, DelEnum.NORMAL.getDel()));
            fieldList = new ArrayList<>();
            fieldList.add(StringConstant.DATA_ID);
            fieldList.add(esData + InvoiceEnum.CONTRACT_ID.getAttr());
            fieldList.add(esData + InvoiceEnum.PAYMENT_ID.getAttr());
            fieldList.add(esData + InvoiceEnum.PAYMENT_SHEET_ID.getAttr());
            fieldList.add(esData + InvoiceEnum.TOTAL_MONEY.getAttr());
            fieldList.add(esData + InvoiceEnum.ORIGIN_ID.getAttr());
            List<PaasFormDataEntityExt> oldRedInvoiceList = esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_INVOICE, boolQueryBuilder, PaasFormDataEntityExt.class,fieldList);
            Map<Long,List<InvoiceRelationshipEntity>> relationshipMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            invoiceRelationshipEntityList.forEach(invoiceRelationshipEntity -> {
                //若是红冲map
                if(idMapping.containsKey(invoiceRelationshipEntity.getInvoiceId())){
                    Long originId = idMapping.getOrDefault(invoiceRelationshipEntity.getInvoiceId(),0L);
                    if(relationshipMap.containsKey(originId)){
                        if(relationshipMap.containsKey(originId)){
                            List<InvoiceRelationshipEntity> invoiceRelationshipEntities = relationshipMap.getOrDefault(originId,new ArrayList<>());
                            invoiceRelationshipEntities.add(invoiceRelationshipEntity);
                        }else {
                            List<InvoiceRelationshipEntity> invoiceRelationshipEntities = new ArrayList<>();
                            invoiceRelationshipEntities.add(invoiceRelationshipEntity);
                            relationshipMap.put(invoiceRelationshipEntity.getInvoiceId(),invoiceRelationshipEntities);
                        }
                    }else {
                        List<InvoiceRelationshipEntity> invoiceRelationshipEntities = new ArrayList<>();
                        invoiceRelationshipEntities.add(invoiceRelationshipEntity);
                        relationshipMap.put(originId,invoiceRelationshipEntities);
                    }
                }else {
                    saasSaveHelp.putInvoiceRelationshipMap(relationshipMap,invoiceRelationshipEntity);
                }
            });

            // 删除发票消息推送
            for (InvoiceEntityExt invoiceEntityExt : invoiceList) {
                Map<Long, Double> contractMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                Map<Long, Double> paymentRefMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                Map<Long, Double> paymentSheetRefMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                List<Long> contractIdList = FastJsonHelper.getJsonArrOrDefaultFromFormData(invoiceEntityExt.getData(), InvoiceEnum.CONTRACT_ID.getAttr(), new JSONArray()).toJavaList(Long.class);
                List<Long> paymentIdList = FastJsonHelper.getJsonArrOrDefaultFromFormData(invoiceEntityExt.getData(), InvoiceEnum.PAYMENT_ID.getAttr(), new JSONArray()).toJavaList(Long.class);
                List<Long> paymentSheetIdList = FastJsonHelper.getJsonArrOrDefaultFromFormData(invoiceEntityExt.getData(), InvoiceEnum.PAYMENT_SHEET_ID.getAttr(), new JSONArray()).toJavaList(Long.class);

                Integer isCancel = getIntegerOrDefaultFromFormData(invoiceEntityExt.getData(), InvoiceEnum.IS_CANCEL.getAttr(), 0);
                List<InvoiceRelationshipEntity> invoiceRelationshipList = null;
                if(Objects.nonNull(relationshipMap)){
                    invoiceRelationshipList = relationshipMap.get(invoiceEntityExt.getId());
                }
                saasUpdateHelp.getInvoiceRefMap(contractMap,paymentRefMap,paymentSheetRefMap,invoiceRelationshipList,null,null,null);
                saasUpdateHelp.getOldInvoiceRefMap(contractMap,paymentRefMap,paymentSheetRefMap,oldRedInvoiceList,contractAmountMap,paymentAmountMap,paymentSheetAmountMap,invoiceEntityExt.getId());
                if (!Objects.equals(isCancel, 1)) {
                    contractIdSet.addAll(contractIdList);
                    planIdSet.addAll(paymentIdList);
                    sheetIdSet.addAll(paymentSheetIdList);
                    InvoiceCancelOrRestorePojo invoiceCancelOrRestorePojo = new InvoiceCancelOrRestorePojo(contractIdList,paymentIdList,paymentSheetIdList,contractMap,paymentRefMap,paymentSheetRefMap);
                    if(CollectionsUtil.isNotEmpty(contractIdList) && CollectionsUtil.isEmpty(paymentIdList) && CollectionsUtil.isEmpty(paymentSheetIdList)){
                        updateInvoiceMoney(corpid,invoiceCancelOrRestorePojo, isCancel,BasicConstant.ONE,XbbRefTypeEnum.CONTRACT.getCode());
                    }else if(CollectionsUtil.isNotEmpty(paymentIdList) && CollectionsUtil.isNotEmpty(contractIdList) && CollectionsUtil.isEmpty(paymentSheetIdList)){
                        updateInvoiceMoney(corpid,invoiceCancelOrRestorePojo, isCancel,BasicConstant.ONE,XbbRefTypeEnum.PAYMENT.getCode());
                    }else if(CollectionsUtil.isNotEmpty(paymentSheetIdList) && CollectionsUtil.isEmpty(paymentIdList)){
                        updateInvoiceMoney(corpid,invoiceCancelOrRestorePojo, isCancel,BasicConstant.ONE,XbbRefTypeEnum.PAYMENT_SHEET.getCode());
                    }
                }
                // 消息推送
                Long dataId = invoiceEntityExt.getId();
                List<String> pushUserList = pushHelper.getUserIdListByPushSetRule(corpid, PushTypeEnum.INVOICE_DEL_PUSH.getCode(), PushTypeEnum.INVOICE_DEL_PUSH.getSubCode(), invoiceDeleteBatchDTO.getLoginUser(), invoiceEntityExt);
                PushRefTypePojo.Options options = new PushRefTypePojo.Options(invoiceEntityExt.getAppId(), invoiceEntityExt.getMenuId(), invoiceEntityExt.getFormId(), dataId, Collections.singletonList(dataId), SaasMarkEnum.SAAS.getCode(), XbbRefTypeEnum.INVOICE.getCode(), XbbRefTypeEnum.INVOICE.getCode());
                MessageRabbitMqDTO messageRabbitMqDTO = new MessageRabbitMqDTO(corpid, pushUserList, Collections.singletonList(dataId), 0, null, I18nMessageUtil.getMessage(InvoicePushConstant.INVOICE_DEL_TITLE), String.format(I18nMessageUtil.getMessage(InvoicePushConstant.INVOICE_DEL_CONTENT), invoiceDeleteBatchDTO.getLoginUser().getName(), invoiceEntityExt.getSerialNo()), null, options);
                baseProducer.sendMessage(PushTypeEnum.INVOICE_DEL_PUSH, messageRabbitMqDTO);
            }
            // 删除发票关联
            InvoiceRelationshipDeleteBatchDTO invoiceRelationshipDeleteBatchDTO = new InvoiceRelationshipDeleteBatchDTO();
            BeanUtil.copyProperties(invoiceDeleteBatchDTO, invoiceRelationshipDeleteBatchDTO);
            idIn.addAll(redIdIn);
            if(CollectionsUtil.isNotEmpty(idIn)) {
                invoiceRelationshipDeleteBatchDTO.setInvoiceIdIn(idIn);
                invoiceRelationshipService.deleteBatchByInvoiceIdIn(invoiceRelationshipDeleteBatchDTO);
            }
            OperateTypeEnum operateTypeEnum = OperateTypeEnum.DELETE;
            if (Objects.equals(1, invoiceDeleteBatchDTO.getIsBusinessRule())) {
                operateTypeEnum = OperateTypeEnum.RULE_DELETE;
            }
            //生成删除日志(区分单个删除和批量删除)
            String userId = invoiceDeleteBatchDTO.getUserId();
            String userName = invoiceDeleteBatchDTO.getLoginUserName();
            String nameStr = StringUtils.join(no, "，");
            //删除应收款
            if(CollectionsUtil.isEmpty(errorDataId)){
                //只有前面的
                receivablesHelper.delReceivablesHandle(paasFormDataEntityExts,operateTypeEnum,userId,userName,corpid,invoiceDeleteBatchDTO.getHttpHeader());
            }
            if(idIn.size() > 1){
                String memo = String.format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_USER_BATCH_DELETE_FORM_DETAIL), userName, XbbRefTypeEnum.INVOICE.getName(), idIn.size());
                List<InfoArrPojo> infoArrPojoList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                InfoArrPojo infoArrPojo = new InfoArrPojo();
                infoArrPojo.setTitle(InvoiceEnum.SHEET_NO.getAttrName());
                infoArrPojo.setContent(nameStr);
                infoArrPojoList.add(infoArrPojo);
                mongoLogHelp.buildLog4InfoArr(infoArrPojoList, corpid, userId, userName, OperateModuleTypeEnum.INVOICE, operateTypeEnum,
                        "", "", memo, invoiceDeleteBatchDTO.getHttpHeader());
            } else if (Objects.equals(idIn.size(), 1)){
                String memo = String.format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_USER_DELETE_WORK), userName, XbbRefTypeEnum.INVOICE.getName(), nameStr);
                mongoLogHelp.buildLog(corpid, userId, userName, OperateModuleTypeEnum.INVOICE, operateTypeEnum,
                        idIn.get(0).toString(), nameStr, memo, invoiceDeleteBatchDTO.getHttpHeader());
            }

            // 动态
            try {
                if (!Objects.equals(DistributorMarkEnum.DISTRIBUTOR.getCode(), invoiceDeleteBatchDTO.getDistributorMark())) {
                    DynamicStrategy dynamicStrategy = dynamicStrategyFactory.getDynamicStrategyByBusinessType(invoiceDeleteBatchDTO.getBusinessType());
                    FormDataDeleteBatchDTO formDataDeleteBatchDTO = BeanUtil.copyProperties(invoiceDeleteBatchDTO, FormDataDeleteBatchDTO.class, true);
                    dynamicStrategy.batchDelete(DynamicDeleteDTO.initDynamicDeleteDTO(formDataDeleteBatchDTO, idIn, paasFormDataExts));
                }
            } catch (Exception e) {
                LOG.error("删除发票动态失败：", e);
            }
        } catch (XbbException e){
            rollBack4LinkEs(invoiceDeleteBatchDTO.getDataIdList(), corpid, contractIdSet, planIdSet, sheetIdSet);
            throw e;
        }catch (Exception e) {
            rollBack4LinkEs(invoiceDeleteBatchDTO.getDataIdList(), corpid, contractIdSet, planIdSet, sheetIdSet);
            LOG.error("invoiceServiceImp.deleteBatch 执行出错：", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
        return invoiceDeleteBatchVO;
    }

    /**
     * 销项发票删除失败、新增发票失败回滚关联业务的es - 同步数据库数据至es（需确保失败后数据库事务回滚结束才同步es）
     * 注：删除的还需回滚发票本身为删除之前的状态
     * @param dataIdList 发票数据id集合
     * @param corpid 公司id
     * @param contractIdIn 关联合同id
     * @param planIdIn 关联应收款id
     * @param sheetIdIn 关联回款单id
     * @author zcp
     * @since v1.0
     * @version v1.0
     */
    private void rollBack4LinkEs(List<Long> dataIdList, String corpid, Collection<Long> contractIdIn, Collection<Long> planIdIn, Collection<Long> sheetIdIn) {
        threadPoolBeanConfig.addUpdateDelThreadPool().execute(() -> {
            try {
                //需要查数据库同步至es内，因此睡眠一小会，确保事务回滚完毕数据库恢复到操作之前的状态
                Thread.sleep(1000L);
                updateRollback(dataIdList, corpid);
                paymentService.updateRollback(planIdIn, corpid);
                contractService.updateRollback(contractIdIn, corpid);
                paymentSheetService.updateRollback(sheetIdIn, corpid);
            } catch (XbbException | InterruptedException e1) {
                LOG.error("InvoiceServiceImpl.rollBack4LinkEs rollback" + e1);
                // 恢复中断状态
                Thread.currentThread().interrupt();
            }
        });
    }

    private void checkRedInvoiceDelete(CheckRedInvoiceDeletePojo checkRedInvoiceDeletePojo,Set<Long> idSet,Map<Long,String> redNoMapping,List<Long> errorDataId,List<String> errorDataNo, Set<String> errorTypeSet){
        Map<Long,Double> contractAmountMap = checkRedInvoiceDeletePojo.getContractOrPurchaseAmountMap();
        Map<Long,Double> paymentAmountMap = checkRedInvoiceDeletePojo.getPaymentOrPayPlanAmountMap();
        Map<Long,Double> paymentSheetAmountMap = checkRedInvoiceDeletePojo.getPaymentSheetOrPaySheetAmountMap();
        Map<Long,Double> paymentInvoiceHistoryMap = checkRedInvoiceDeletePojo.getPaymentOrPayPlanInvoiceHistoryMap();
        Map<Long,Double> paymentSheetInvoiceHistoryMap = checkRedInvoiceDeletePojo.getPaymentSheetOrPaySheetInvoiceHistoryMap();
        Map<Long,Double> contractInvoiceHistoryMap = checkRedInvoiceDeletePojo.getContractOrPurchaseInvoiceHistoryMap();
        Map<Long,List<Long>> invoiceRefContractMap = checkRedInvoiceDeletePojo.getInvoiceRefContractOrPurchaseMap();
        Map<Long,List<Long>> invoiceRefPaymentMap = checkRedInvoiceDeletePojo.getInvoiceRefPaymentOrPayPlanMap();
        Map<Long,List<Long>> invoiceRefPaymentSheetMap = checkRedInvoiceDeletePojo.getInvoiceRefPaymentSheetOrPaySheetMap();
        Map<Long,Map<Long,Double>> contractRedMoneyMap = checkRedInvoiceDeletePojo.getContractOrPurchaseRedMoneyMap();
        Map<Long,Map<Long,Double>> paymentRedMoneyMap = checkRedInvoiceDeletePojo.getPaymentOrPayPlanRedMoneyMap();
        Map<Long,Map<Long,Double>> paymentSheetRedMoneyMap = checkRedInvoiceDeletePojo.getPaymentSheetOrPaySheetRedMoneyMap();
        //新数据计算可开票金额以及总金额
        if(CollectionsUtil.isNotEmpty(idSet)) {
            for (Long id : idSet) {
                if(Objects.nonNull(invoiceRefContractMap)) {
                    if (invoiceRefContractMap.containsKey(id)) {
                        List<Long> contractIdList = invoiceRefContractMap.get(id);
                        if (CollectionsUtil.isNotEmpty(contractIdList)) {
                            for (Long contractId : contractIdList) {
                                double contractInvoiceHistory = contractInvoiceHistoryMap.getOrDefault(contractId, 0D);
                                double contractAmount = contractAmountMap.getOrDefault(contractId, 0D);
                                Map<Long,Double> refRedInvoiceMap = contractRedMoneyMap.getOrDefault(id,new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY));
                                double redInvoiceAmount = refRedInvoiceMap.getOrDefault(contractId, 0D);
                                //删除红冲发票 根据所关联的业务的可开票的金额 加上 红冲的金额(负的) 如果小于零说明不够开,不允许删除
                                // 举个例子，就是5000的合同，合同新建200的发票，然后红冲200发票，这时候合同还能开5000发票，这时候去删除红冲发票，肯定就会有问题，如果删除的话，5000的合同不就开了5200的票么，所以不让删除
                                if (Arith.add(Arith.sub(contractAmount, contractInvoiceHistory), redInvoiceAmount) < 0) {
                                    errorDataNo.add(redNoMapping.getOrDefault(id, ""));
                                    errorDataId.add(id);
                                    errorTypeSet.add(I18nMessageUtil.getMessage(ErrorMessageConstant.RECEIVABLES_HAS_PAYMENT_SHEET));
                                    break;
                                }
                            }
                        }
                    }
                }
                if(Objects.nonNull(invoiceRefPaymentMap)) {
                    if (invoiceRefPaymentMap.containsKey(id)) {
                        List<Long> paymentIdList = invoiceRefPaymentMap.get(id);
                        if(CollectionsUtil.isNotEmpty(paymentIdList)){
                            for(Long paymentId : paymentIdList){
                                double paymentInvoiceHistory = paymentInvoiceHistoryMap.getOrDefault(paymentId,0D);
                                double paymentAmount = paymentAmountMap.getOrDefault(paymentId,0D);
                                //double redInvoiceAmount = redMoneyMap.getOrDefault(id,0D);
                                Map<Long,Double> refRedInvoiceMap = paymentRedMoneyMap.getOrDefault(id,new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY));
                                double redInvoiceAmount = refRedInvoiceMap.getOrDefault(paymentId, 0D);
                                if (Arith.add(Arith.sub(paymentAmount, paymentInvoiceHistory), redInvoiceAmount) < 0) {
                                    errorDataNo.add(redNoMapping.getOrDefault(id, ""));
                                    errorDataId.add(id);
                                    errorTypeSet.add(I18nMessageUtil.getMessage(ErrorMessageConstant.RECEIVABLES_HAS_PAYMENT_SHEET));
                                    break;
                                }
                            }
                        }
                    }
                }
                if(Objects.nonNull(invoiceRefPaymentSheetMap)){
                    if (invoiceRefPaymentSheetMap.containsKey(id)) {
                        List<Long> paymentSheetIdList = invoiceRefPaymentSheetMap.get(id);
                        if(CollectionsUtil.isNotEmpty(paymentSheetIdList)){
                            for(Long paymentSheetId : paymentSheetIdList){
                                double paymentSheetInvoiceHistory = paymentSheetInvoiceHistoryMap.getOrDefault(paymentSheetId,0D);
                                double paymentSheetAmount = paymentSheetAmountMap.getOrDefault(paymentSheetId,0D);
                                //double redInvoiceAmount = redMoneyMap.getOrDefault(id,0D);
                                Map<Long,Double> refRedInvoiceMap = paymentSheetRedMoneyMap.getOrDefault(id,new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY));
                                double redInvoiceAmount = refRedInvoiceMap.getOrDefault(paymentSheetId, 0D);
                                if (Arith.add(Arith.sub(paymentSheetAmount, paymentSheetInvoiceHistory), redInvoiceAmount) < 0) {
                                    errorDataNo.add(redNoMapping.getOrDefault(id, ""));
                                    errorDataId.add(id);
                                    errorTypeSet.add(I18nMessageUtil.getMessage(ErrorMessageConstant.RECEIVABLES_HAS_PAYMENT_SHEET));
                                    break;
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    /**
     * 根据金额明细获取开票金额
     * @param set
     * @param queryMap
     * @param invoiceHistoryMap
     * @param amountMap
     * @param invoiceRefContractMap
     * @param invoiceRefPaymentMap
     * @param invoiceRefPaymentSheetMap
     * @param attr
     * @param corpid
     * @param xbbRefTypeEnum
     * @throws XbbException
     */
    private void getInvoiceAmountByRelationship(Set<Long> set,Map<String,Object> queryMap,Map<Long,Double> invoiceHistoryMap,Map<Long,Double> amountMap,
                                                Map<Long,List<Long>> invoiceRefContractMap,Map<Long,List<Long>> invoiceRefPaymentMap,Map<Long,List<Long>> invoiceRefPaymentSheetMap,String attr,String corpid,XbbRefTypeEnum xbbRefTypeEnum) throws XbbException{
        if(CollectionsUtil.isNotEmpty(set)){
            queryMap.remove("invoiceIdIn");
            queryMap.put(attr,set);
            List<InvoiceRelationshipEntity> refInvoiceList = invoiceRelationshipModel.findEntitys(queryMap);
            //还原
            queryMap.remove(attr);
            if(Objects.equals(xbbRefTypeEnum,XbbRefTypeEnum.PAYMENT)) {
                refInvoiceList.forEach(item -> {
                    saasSaveHelp.addMapNormal(invoiceHistoryMap, item.getPaymentId(), item.getMoney());
                    List<Long> paymentId = new ArrayList<>();
                    List<Long> contractId = new ArrayList<>();
                    paymentId.add(item.getPaymentId());
                    contractId.add(item.getContractId());
                    if(CollectionsUtil.isNotEmpty(paymentId)) {
                        invoiceRefPaymentMap.put(item.getInvoiceId(), paymentId);
                    }
                    if(CollectionsUtil.isNotEmpty(contractId)) {
                        invoiceRefContractMap.put(item.getInvoiceId(), contractId);
                    }
                });
            }
            if(Objects.equals(xbbRefTypeEnum,XbbRefTypeEnum.PAYMENT_SHEET)) {
                refInvoiceList.forEach(item -> {
                    saasSaveHelp.addMapNormal(invoiceHistoryMap, item.getPaymentSheetId(), item.getMoney());
                    List<Long> paymentSheetId = new ArrayList<>();
                    List<Long> contractId = new ArrayList<>();
                    paymentSheetId.add(item.getPaymentSheetId());
                    contractId.add(item.getContractId());
                    if(CollectionsUtil.isNotEmpty(paymentSheetId)){
                        invoiceRefPaymentSheetMap.put(item.getInvoiceId(),paymentSheetId);
                    }
                    if(CollectionsUtil.isNotEmpty(contractId)){
                        invoiceRefContractMap.put(item.getInvoiceId(),contractId);
                    }
                });
            }
            if(Objects.equals(xbbRefTypeEnum,XbbRefTypeEnum.CONTRACT)) {
                refInvoiceList.forEach(item -> {
                    saasSaveHelp.addMapNormal(invoiceHistoryMap, item.getContractId(), item.getMoney());
                    List<Long> contractId = new ArrayList<>();
                    contractId.add(item.getContractId());
                    if(CollectionsUtil.isNotEmpty(contractId)){
                        invoiceRefContractMap.put(item.getInvoiceId(),contractId);
                    }
                });
            }
            Map<String,Object> map = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            map.put("corpid",corpid);
            map.put("del",BasicConstant.ZERO);
            if(Objects.isNull(amountMap)){
                amountMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            }
            if(Objects.equals(xbbRefTypeEnum,XbbRefTypeEnum.CONTRACT)){
                map.put("idIn",set);
                List<ContractEntityExt> contractEntityExtList = contractModel.findEntitys(map);
                for(ContractEntityExt contractEntityExt : contractEntityExtList) {
                    amountMap.put(contractEntityExt.getId(), getDoubleOrDefaultFromFormData(contractEntityExt.getData(), ContractEnum.AMOUNT.getAttr(), 0D));
                }
            }
            if(Objects.equals(xbbRefTypeEnum,XbbRefTypeEnum.PAYMENT)){
                map.put("idIn",set);
                List<PaymentEntityExt> paymentEntityExts = paymentModel.findEntitys(map);
                for(PaymentEntityExt paymentEntityExt : paymentEntityExts){
                    amountMap.put(paymentEntityExt.getId(), getDoubleOrDefaultFromFormData(paymentEntityExt.getData(), PaymentEnum.AMOUNT.getAttr(), 0D));
                }
            }
            if(Objects.equals(xbbRefTypeEnum,XbbRefTypeEnum.PAYMENT_SHEET)){
                map.put("idIn",set);
                List<PaymentSheetEntityExt> paymentSheetEntityExts = paymentSheetModel.findEntitys(map);
                for(PaymentSheetEntityExt paymentSheetEntityExt : paymentSheetEntityExts){
                    amountMap.put(paymentSheetEntityExt.getId(),getDoubleOrDefaultFromFormData(paymentSheetEntityExt.getData(),PaymentSheetEnum.AMOUNT.getAttr(),0D));
                }
            }
        }
    }

    @Override
    public ListAppVO formatInvoiceAppList(FormDataListDTO formDataListDTO, List<PaasFormDataEntityExt> esEntities, Integer totalCount) throws XbbException {
        List<AppListPojo> appListPojos = new ArrayList<>();
        // TODO long.rao 目前列表页靠这个字段来判断发票状态0为正常，1为红冲，2为作废
        Integer statusFilter = formDataListDTO.getStatusFilter();

        for(PaasFormDataEntityExt entity : esEntities){
            Long invoiceId = entity.getDataId();
            JSONObject data = entity.getData();
            JSONObject superScript = new JSONObject();
            JSONObject others = new JSONObject();
            // 其他
            if(Objects.equals(statusFilter, 1)){
                others.put("isRed", BasicConstant.ONE);
            }
            commonHelp.setInvoiceInfo(data, superScript, others);

            List<SummaryDataPoJo> summaryList = FastJsonHelper.getJsonArrOrDefaultFromFormData(data, BasicConstant.SUMMARY_LIST, new JSONArray()).toJavaList(SummaryDataPoJo.class);
            List<SummaryDataPoJo> lablesList = FastJsonHelper.getJsonArrOrDefaultFromFormData(data, BasicConstant.LABELS_LIST, new JSONArray()).toJavaList(SummaryDataPoJo.class);
            List<FormTitlePoJo> titleList = FastJsonHelper.getJsonArrOrDefaultFromFormData(data, BasicConstant.TITLE_LIST, new JSONArray()).toJavaList(FormTitlePoJo.class);
            if (titleList.isEmpty()) {
                titleList.add(commonHelp.setTitle(entity.getSerialNo()));
            }

            appListPojos.add(new AppListPojo(invoiceId, titleList, summaryList, superScript, lablesList, others, entity.getAppId(), entity.getMenuId(), entity.getFormId()));
        }
        ListAppVO listAppVO = new ListAppVO();
        listAppVO.setList(appListPojos);
        listAppVO.setTotalCount(totalCount);
        return  listAppVO;
    }

    @Override
    public void formatLinkAddExplain(HandlerExplainInLinkItemDTO handlerExplainInLinkItemDTO) throws XbbException {
        JSONObject linkFormData = handlerExplainInLinkItemDTO.getLinkFormData();
        JSONArray jsonArray = new JSONArray();
        String corpid = handlerExplainInLinkItemDTO.getCorpid();
        XbbRefTypeEnum xbbRefTypeEnum = XbbRefTypeEnum.getByCode(handlerExplainInLinkItemDTO.getLinkBusinessType());
        List<PaasFormDataEntityExt> paasFormDataEntityExts = new ArrayList<>();
        paasFormDataEntityExts.add(handlerExplainInLinkItemDTO.getPaasFormDataEntityExt());
        Map<String,List<PaasFormDataEntityExt>> paymentSheetMap = splitPaymentSheet(paasFormDataEntityExts,handlerExplainInLinkItemDTO.getCorpid());
        Map<Long,Double> contractIdToUnInvoiceAmountMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long,Double> refIdToUnInvoiceAmountMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        verifySingleData(xbbRefTypeEnum,handlerExplainInLinkItemDTO.getPaasFormDataEntityExt(),jsonArray, corpid,paymentSheetMap,contractIdToUnInvoiceAmountMap,refIdToUnInvoiceAmountMap);
        Long linkDataId = handlerExplainInLinkItemDTO.getLinkDataId();
        List<FieldAttrEntity> explainList = handlerExplainInLinkItemDTO.getExplainList();
        boolean isPrePaymentSheet = Objects.equals(linkFormData.getString(PaymentSheetEnum.PAYMENT_SHEET_TYPE.getAttr()),PaymentSheetTypeEnum.PREPAYMENT.getCode());
        PaasFormDataEntityExt paasFormDataEntityExt = handlerExplainInLinkItemDTO.getPaasFormDataEntityExt();
        FieldAttrEntity linkCustomerField = new FieldAttrEntity();
        FieldAttrEntity linkContractField = new FieldAttrEntity();
        FieldAttrEntity linkPaymentField = new FieldAttrEntity();
        FieldAttrEntity linkPaymentSheetField = new FieldAttrEntity();
        FieldAttrEntity linkPaymentRelationshipField = new FieldAttrEntity();
        for(FieldAttrEntity fieldAttrEntity :explainList) {
            if (Objects.equals(fieldAttrEntity.getAttr(), InvoiceEnum.CUSTOMER_NAME.getAttr())) {
                linkCustomerField = fieldAttrEntity;
            }
            if (Objects.equals(fieldAttrEntity.getAttr(), InvoiceEnum.CONTRACT_ID.getAttr())) {
                linkContractField = fieldAttrEntity;
            }
            if (Objects.equals(fieldAttrEntity.getAttr(), InvoiceEnum.PAYMENT_ID.getAttr())) {
                linkPaymentField = fieldAttrEntity;
            }
            if(Objects.equals(fieldAttrEntity.getAttr(),InvoiceEnum.PAYMENT_SHEET_ID.getAttr())){
                linkPaymentSheetField = fieldAttrEntity;
            }
            if(Objects.equals(fieldAttrEntity.getAttr(),InvoiceEnum.PAYMENT_RELATIONSHIP.getAttr())){
                linkPaymentRelationshipField = fieldAttrEntity;
            }
        }
        DefaultAttrPoJo defaultAttrPoJo;
        JSONObject jsonObject;
        JSONArray linkCustomerArr;
        JSONArray linkContractArr;
        RedundantTemplateTypeEnum redundantTemplateTypeEnum = RedundantTemplateTypeEnum.getByCode(handlerExplainInLinkItemDTO.getLinkBusinessType());
        switch (redundantTemplateTypeEnum) {
            case CUSTOMER:
                String customerName = FastJsonHelper.getStringOrDefaultFromFormData(linkFormData, CustomerManagementEnum.NAME.getAttr(), "");
                linkCustomerField.setDefaultAttr(saasUpdateHelp.getDefaultAttrPojo(linkDataId, customerName));
                break;
            case CONTRACT:
                linkCustomerArr = FastJsonHelper.getJsonArrOrDefaultFromFormData(linkFormData,ContractEnum.LINK_CUSTOMER.getAttr(), new JSONArray());
                linkCustomerField.setDefaultAttr(saasUpdateHelp.getDefaultAttrPojo(linkCustomerArr));
                String contractNo = paasFormDataEntityExt.getSerialNo();
                linkContractField.setDefaultAttr(saasUpdateHelp.getDefaultAttrPojo(linkDataId,contractNo));
                break;
            case PAYMENT:
                if (Objects.equals(paasFormDataEntityExt.getSysLong10(), ModelTypeEnum.INVOICE.getCode())) {
                    throw new XbbException(SystemErrorCodeEnum.API_ERROR_100028, ErrorMessageConstant.PAYMENT_INVOICE_MUST_NO_MODEL_INVOICE);
                }
                linkCustomerArr = FastJsonHelper.getJsonArrOrDefaultFromFormData(linkFormData,PaymentEnum.CUSTOMER.getAttr(), new JSONArray());
                linkCustomerField.setDefaultAttr(saasUpdateHelp.getDefaultAttrPojo(linkCustomerArr));
                linkContractArr = FastJsonHelper.getJsonArrOrDefaultFromFormData(linkFormData,PaymentEnum.CONTRACT.getAttr(), new JSONArray());
                linkContractField.setDefaultAttr(saasUpdateHelp.getDefaultAttrPojo(linkContractArr));
                String paymentNo = paasFormDataEntityExt.getSerialNo();
                linkPaymentField.setDefaultAttr(saasUpdateHelp.getDefaultAttrPojo(linkDataId,paymentNo));
                defaultAttrPoJo = new DefaultAttrPoJo();
                defaultAttrPoJo.setUseLinkValue(BasicConstant.ONE);
                jsonObject = new JSONObject();
                jsonObject.put("text", I18nMessageUtil.getMessage(PaymentRelationshipEnum.PAYMENT.getAlias()));
                jsonObject.put("value",PaymentRelationshipEnum.PAYMENT.getCode());
                defaultAttrPoJo.setLinkFormValue(jsonObject);
                linkPaymentRelationshipField.setDefaultAttr(defaultAttrPoJo);
                break;
            case PAYMENT_SHEET:
                List<PaasFormDataEntityExt> paymentSheetEntityExtList = null;
                List<PaasFormDataEntityExt> addList = new ArrayList<>();
                List<PaasFormDataEntityExt> removeList = new ArrayList<>();
                List<PaasFormDataEntityExt> removeSubPaymentSheet = new ArrayList<>();
                if(CollectionsUtil.isNotEmpty(paasFormDataEntityExts)) {
                    if (Objects.nonNull(paasFormDataEntityExt.getUuid())) {
                        if (paymentSheetMap.containsKey(paasFormDataEntityExt.getUuid())) {
                            paymentSheetEntityExtList = paymentSheetMap.get(paasFormDataEntityExt.getUuid());
                        }
                        if(CollectionsUtil.isNotEmpty(paymentSheetEntityExtList)){
                            for(PaasFormDataEntityExt paasFormDataEntity : paymentSheetEntityExtList){
                                double refUnInvoiceAmount = refIdToUnInvoiceAmountMap.getOrDefault(paasFormDataEntity.getId(),0D);
                                if(refUnInvoiceAmount == BasicConstant.ZERO_DOUBLE){
                                    removeSubPaymentSheet.add(paasFormDataEntity);
                                }
                            }
                            if(!Objects.equals(paymentSheetEntityExtList.size(),removeSubPaymentSheet.size())){
                                paymentSheetEntityExtList.removeAll(removeSubPaymentSheet);
                            }
                            addList.addAll(paymentSheetEntityExtList);
                            removeList.add(paasFormDataEntityExt);
                        }
                    }
                    paasFormDataEntityExts.removeAll(removeList);
                    paasFormDataEntityExts.addAll(addList);
                }
                linkCustomerArr = FastJsonHelper.getJsonArrOrDefaultFromFormData(linkFormData,PaymentSheetEnum.CUSTOMER_ID.getAttr(), new JSONArray());
                linkCustomerField.setDefaultAttr(saasUpdateHelp.getDefaultAttrPojo(linkCustomerArr));
                if(!isPrePaymentSheet){
                    JSONArray contractArray = FastJsonHelper.getJsonArrOrDefaultFromFormData(linkFormData,PaymentSheetEnum.CONTRACT.getAttr(),new JSONArray());
                    Map<Long,Object> contractMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                    for(int i=0;i<contractArray.size();i++){
                        JSONObject object = contractArray.getJSONObject(i);
                        contractMap.put(object.getLong(BasicConstant.ID),object);
                    }
                    if(CollectionsUtil.isNotEmpty(removeSubPaymentSheet)){
                        for(PaasFormDataEntityExt paasFormDataEntity : removeSubPaymentSheet){
                            Long id = paasFormDataEntity.getData().getJSONArray(PaymentSheetEnum.CONTRACT.getAttr()).getLong(BasicConstant.ZERO);
                            if(contractMap.get(id) != null){
                                Object contractObject = contractMap.get(id);
                                contractArray.remove(contractObject);
                            }
                        }
                    }
                    linkContractField.setDefaultAttr(saasUpdateHelp.getDefaultAttrPojo(contractArray));

                }
                JSONArray paymentSheetArr = new JSONArray();
                if(CollectionsUtil.isNotEmpty(paasFormDataEntityExts)){
                    for(PaasFormDataEntityExt paymentSheetEntity : paasFormDataEntityExts){
                        JSONObject json = new JSONObject();
                        JSONObject data = paymentSheetEntity.getData();
                        json.put(StringConstant.SAAS_LINK_BUSINESS_ID,paymentSheetEntity.getId());
                        json.put(StringConstant.SAAS_LINK_BUSINESS_NAME,paymentSheetEntity.getSerialNo());
                        json.put(InvoiceConstant.PAYMENT_SHEET_TYPE, data.getString(PaymentSheetEnum.PAYMENT_SHEET_TYPE.getAttr()));
                        paymentSheetArr.add(json);
                    }
                    linkPaymentSheetField.setDefaultAttr(saasUpdateHelp.getDefaultAttrPojo(paymentSheetArr));
                }
                defaultAttrPoJo = new DefaultAttrPoJo();
                defaultAttrPoJo.setUseLinkValue(BasicConstant.ONE);
                jsonObject = new JSONObject();
                jsonObject.put("text",I18nMessageUtil.getMessage(PaymentRelationshipEnum.PAYMENT_SHEET.getAlias()));
                jsonObject.put("value",PaymentRelationshipEnum.PAYMENT_SHEET.getCode());
                defaultAttrPoJo.setLinkFormValue(jsonObject);
                linkPaymentRelationshipField.setDefaultAttr(defaultAttrPoJo);
                break;
            default:
                break;
        }
    }

    private Map<String,List<PaasFormDataEntityExt>> splitPaymentSheet(List<PaasFormDataEntityExt> paasFormDataEntityExtList,String corpid) throws XbbException{
        Set<String> uuidList = new HashSet<>();
        Map<String,List<PaasFormDataEntityExt>> paymentSheetMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        List<PaasFormDataEntityExt> subPaymentSheetList = new ArrayList<>();
        paasFormDataEntityExtList.forEach(paasFormDataEntityExt -> {
            if (StringUtil.isNotEmpty(paasFormDataEntityExt.getUuid())) {
                uuidList.add(paasFormDataEntityExt.getUuid());
            }
        });
        if(CollectionsUtil.isNotEmpty(uuidList)) {
            subPaymentSheetList = fundHelp.getChildEsDataListByParentUuids(XbbRefTypeEnum.PAYMENT_SHEET, corpid, uuidList, null, null);
        }
        subPaymentSheetList.forEach(subPaasFormDataEntityExt -> {
            List<PaasFormDataEntityExt> paymentSheetList = new ArrayList<>();
            if(paymentSheetMap.containsKey(subPaasFormDataEntityExt.getUuid())){
                paymentSheetMap.get(subPaasFormDataEntityExt.getUuid()).add(subPaasFormDataEntityExt);
            }else {
                paymentSheetList.add(subPaasFormDataEntityExt);
                paymentSheetMap.put(subPaasFormDataEntityExt.getUuid(),paymentSheetList);
            }
        });
        return paymentSheetMap;
    }

    @Override
    public void batchEditAttr(InvoiceEditAttrUpdateDTO invoiceEditAttrUpdateDTO) throws XbbException {
        try {
            List<InvoiceUpdateDTO> invoiceList = new ArrayList<>();
            invoiceEditAttrUpdateDTO.getDataIdList().forEach((item)->{
                InvoiceUpdateDTO invoiceUpdateDTO = new InvoiceUpdateDTO();
                invoiceUpdateDTO.setId(item);
                JSONObject data = ProSaveHelp.getBatchUpdateData(invoiceEditAttrUpdateDTO.getFieldEditedList());
                invoiceUpdateDTO.setData(data);
                invoiceList.add(invoiceUpdateDTO);
            });
            List<InvoiceEntityExt> invoiceEntityList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            if (!invoiceList.isEmpty()) {
                Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                param.put("corpid", invoiceEditAttrUpdateDTO.getCorpid());
                param.put("idIn", invoiceEditAttrUpdateDTO.getDataIdList());
                invoiceEntityList = invoiceModel.findEntitys(param);
                if (Objects.isNull(invoiceEntityList)){
                    throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
                }
                InvoiceUpdateBatchDTO invoiceUpdateBatchDTO = new InvoiceUpdateBatchDTO();
                BeanUtil.copyProperties(invoiceEditAttrUpdateDTO, invoiceUpdateBatchDTO);
                invoiceUpdateBatchDTO.setInvoiceList(invoiceList);
                updateBatch(invoiceUpdateBatchDTO);
            }

            // 批量编辑日志
            List<String> updataItemList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            List<Long> dataIdList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            for (InvoiceEntityExt item : invoiceEntityList) {
                dataIdList.add(item.getId());
                String serialNo = item.getSerialNo();
                updataItemList.add(serialNo);
            }
            String updataItem = StringUtils.join(updataItemList, "，");
            String userId = invoiceEditAttrUpdateDTO.getUserId();
            String corpid = invoiceEditAttrUpdateDTO.getCorpid();
            String loginUserName = invoiceEditAttrUpdateDTO.getLoginUserName();
            // 标签特殊处理
            Integer fieldType = invoiceEditAttrUpdateDTO.getFieldType();
            Boolean isFieldDependence = invoiceEditAttrUpdateDTO.getIsFieldDependence();
            logHelp.analysisLabel(corpid, fieldType, isFieldDependence,invoiceEditAttrUpdateDTO.getLogFieldEditedList());

            String changedLogItemsStr = logHandleHelp.getChangedLogItemsStr(invoiceEditAttrUpdateDTO.getLogFieldEditedList());
            if(dataIdList.size() > 1 ){
                String memo = String.format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_USER_UPDATE_FORM_DATA_BATCH_ATTR), loginUserName, XbbRefTypeEnum.INVOICE.getName(),
                        changedLogItemsStr, dataIdList.size());
                List<InfoArrPojo> infoArrPojoList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                InfoArrPojo infoArrPojo = new InfoArrPojo();
                infoArrPojo.setTitle(XbbRefTypeEnum.INVOICE.getName());
                infoArrPojo.setContent(updataItem);
                infoArrPojoList.add(infoArrPojo);
                mongoLogHelp.buildLog4InfoArr(infoArrPojoList, corpid, userId, loginUserName, OperateModuleTypeEnum.INVOICE, OperateTypeEnum.EDIT,
                        "", "", memo, invoiceEditAttrUpdateDTO.getHttpHeader());
            } else if (Objects.equals(dataIdList.size(), 1)){
                String memo = String.format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_USER_UPDATE_FORM_DATA_ATTR), loginUserName, XbbRefTypeEnum.INVOICE.getName(), updataItem,
                        changedLogItemsStr);
                mongoLogHelp.buildLog(corpid, userId, loginUserName, OperateModuleTypeEnum.INVOICE, OperateTypeEnum.EDIT,
                        dataIdList.get(0).toString(), updataItem, memo, invoiceEditAttrUpdateDTO.getHttpHeader());
            }
        } catch (XbbException e) {
            throw e;
        } catch (Exception e) {
            LOG.error("invoiceService.batchEditAttr 执行出错：", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
    }

    /**
     * 新建时格式化解释
     *
     * @param formatExplainDTO 入参
     * @throws XbbException 异常
     */
    @Override
    public void formatAddExplain(FormatExplainDTO formatExplainDTO) throws XbbException {
        List<FieldAttrEntity> explainList = formatExplainDTO.getExplainList();
        //获取当前处于什么模式
        Long modelType = fundSetService.getModelType(formatExplainDTO.getCorpid(),XbbRefTypeEnum.CRM);
        explainList.forEach((item) -> {
            if (Objects.equals(item.getAttr(), InvoiceEnum.APPLY_USER.getAttr())) {
                item.setDefaultAttr(defaultAttrHelp.setUserDefaultAttrPoJo(formatExplainDTO.getUserId(), formatExplainDTO.getLoginUser().getName(),formatExplainDTO.getLoginUser().getAvatar()));
            }
            if(Objects.equals(modelType,ModelTypeEnum.INVOICE.getCode())){
                if(Objects.equals(item.getAttr(), InvoiceEnum.PAYMENT_RELATIONSHIP.getAttr())
                        || Objects.equals(item.getAttr(),InvoiceEnum.PAYMENT_ID.getAttr())
                        || Objects.equals(item.getAttr(),InvoiceEnum.PAYMENT_SHEET_ID.getAttr())){
                    item.setVisible(BasicConstant.ZERO);
                }
            }
        });
    }

    @Override
    public void formatBatchLinkAddExplain(HandlerExplainBatchLinkItemDTO handlerExplainBatchLinkItemDTO) throws XbbException {
        List<PaasFormDataEntityExt> paasFormDataEntityExts = handlerExplainBatchLinkItemDTO.getPaasFormDataEntityExts();
        Integer linkBusinessType = handlerExplainBatchLinkItemDTO.getLinkBusinessType();
        String corpid = handlerExplainBatchLinkItemDTO.getCorpid();
        XbbRefTypeEnum xbbRefTypeEnum = XbbRefTypeEnum.getByCode(linkBusinessType);
        JSONArray jsonArray = new JSONArray();
        Map<String,List<PaasFormDataEntityExt>> paymentSheetMap = splitPaymentSheet(paasFormDataEntityExts,handlerExplainBatchLinkItemDTO.getCorpid());
        Map<Long,Double> contractIdToUnInvoiceAmountMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long,Double> refIdToUnInvoiceAmountMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        verifyData(xbbRefTypeEnum, paasFormDataEntityExts, jsonArray, corpid,paymentSheetMap,contractIdToUnInvoiceAmountMap,refIdToUnInvoiceAmountMap);
        List<FieldAttrEntity> explainList = handlerExplainBatchLinkItemDTO.getExplainList();
        FieldAttrEntity linkCustomerField = new FieldAttrEntity();
        FieldAttrEntity linkContractField = new FieldAttrEntity();
        FieldAttrEntity linkPaymentField = new FieldAttrEntity();
        FieldAttrEntity linkPaymentSheetField = new FieldAttrEntity();
        FieldAttrEntity linkPaymentRelationshipField = new FieldAttrEntity();
        for (FieldAttrEntity fieldAttrEntity : explainList) {
            String attr = fieldAttrEntity.getAttr();
            if (Objects.equals(attr, InvoiceEnum.CUSTOMER_NAME.getAttr())) {
                linkCustomerField = fieldAttrEntity;
            }
            if (Objects.equals(attr, InvoiceEnum.CONTRACT_ID.getAttr())) {
                linkContractField = fieldAttrEntity;
            }
            if (Objects.equals(attr, InvoiceEnum.PAYMENT_ID.getAttr())) {
                linkPaymentField = fieldAttrEntity;
            }
            if(Objects.equals(attr,InvoiceEnum.PAYMENT_SHEET_ID.getAttr())){
                linkPaymentSheetField = fieldAttrEntity;
            }
            if(Objects.equals(attr,InvoiceEnum.PAYMENT_RELATIONSHIP.getAttr())){
                linkPaymentRelationshipField = fieldAttrEntity;
            }
        }

        JSONArray customerArr = new JSONArray();
        JSONArray contractArr = new JSONArray();
        JSONArray paymentArr = new JSONArray();
        JSONArray paymentSheetArr = new JSONArray();
        Set<JSONObject> copyContract = new HashSet<>();
        JSONObject jsonObject;
        DefaultAttrPoJo defaultAttrPoJo;
        Set<Long> contractIdSet = new HashSet<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        switch (xbbRefTypeEnum) {
            case CONTRACT:
                for (PaasFormDataEntityExt paasFormDataEntityExt : paasFormDataEntityExts) {
                    JSONObject data = paasFormDataEntityExt.getData();
                    customerArr = FastJsonHelper.getJsonArrOrDefaultFromFormData(data, ContractEnum.LINK_CUSTOMER.getAttr(), jsonArray);
                    JSONObject contractObj = new JSONObject();
                    contractObj.put(StringConstant.SAAS_LINK_BUSINESS_ID, paasFormDataEntityExt.getId());
                    contractObj.put(StringConstant.SAAS_LINK_BUSINESS_NAME, paasFormDataEntityExt.getSerialNo());
                    contractArr.add(contractObj);
                }
                linkCustomerField.setDefaultAttr(saasUpdateHelp.getDefaultAttrPojo(customerArr));
                linkContractField.setDefaultAttr(saasUpdateHelp.getDefaultAttrPojo(contractArr));
                break;
            case PAYMENT:
                for (PaasFormDataEntityExt paasFormDataEntityExt : paasFormDataEntityExts) {
                    JSONObject data = paasFormDataEntityExt.getData();
                    customerArr = FastJsonHelper.getJsonArrOrDefaultFromFormData(data, PaymentEnum.CUSTOMER.getAttr(), jsonArray);
                    contractArr = FastJsonHelper.getJsonArrOrDefaultFromFormData(data, PaymentEnum.CONTRACT.getAttr(), jsonArray);
                    if(CollectionsUtil.isNotEmpty(contractArr)) {
                        copyContract.add(contractArr.getJSONObject(0));
                    }
                    JSONObject paymentObj = new JSONObject();
                    paymentObj.put(StringConstant.SAAS_LINK_BUSINESS_ID, paasFormDataEntityExt.getId());
                    paymentObj.put(StringConstant.SAAS_LINK_BUSINESS_NAME, paasFormDataEntityExt.getSerialNo());
                    paymentArr.add(paymentObj);
                }
                contractArr.clear();
                contractArr.addAll(copyContract);
                linkCustomerField.setDefaultAttr(saasUpdateHelp.getDefaultAttrPojo(customerArr));
                linkContractField.setDefaultAttr(saasUpdateHelp.getDefaultAttrPojo(contractArr));
                linkPaymentField.setDefaultAttr(saasUpdateHelp.getDefaultAttrPojo(paymentArr));
                defaultAttrPoJo = new DefaultAttrPoJo();
                defaultAttrPoJo.setUseLinkValue(BasicConstant.ONE);
                jsonObject = new JSONObject();
                jsonObject.put("text",I18nMessageUtil.getMessage(PaymentRelationshipEnum.PAYMENT.getAlias()));
                jsonObject.put("value",PaymentRelationshipEnum.PAYMENT.getCode());
                defaultAttrPoJo.setLinkFormValue(jsonObject);
                linkPaymentRelationshipField.setDefaultAttr(defaultAttrPoJo);
                break;
            case PAYMENT_SHEET:
                List<PaasFormDataEntityExt> removeSubPaymentSheet = new ArrayList<>();
                List<PaasFormDataEntityExt> addList = new ArrayList<>();
                List<PaasFormDataEntityExt> removeList = new ArrayList<>();
                if(CollectionsUtil.isNotEmpty(paasFormDataEntityExts)) {
                    for (PaasFormDataEntityExt paasFormDataEntityExt : paasFormDataEntityExts) {
                        double refUnInvoiceAmount = refIdToUnInvoiceAmountMap.getOrDefault(paasFormDataEntityExt.getId(), 0D);
                        if (refUnInvoiceAmount == BasicConstant.ZERO_DOUBLE) {
                            removeSubPaymentSheet.add(paasFormDataEntityExt);
                        }
                    }
                    for (PaasFormDataEntityExt paasFormDataEntityExt : paasFormDataEntityExts) {
                        if (Objects.nonNull(paasFormDataEntityExt.getUuid())) {
                            if (paymentSheetMap.containsKey(paasFormDataEntityExt.getUuid())) {
                                List<PaasFormDataEntityExt> paymentSheetEntityExtList = paymentSheetMap.get(paasFormDataEntityExt.getUuid());
                                addList.addAll(paymentSheetEntityExtList);
                                removeList.add(paasFormDataEntityExt);
                            }
                        }
                    }
                }
                paasFormDataEntityExts.removeAll(removeList);
                paasFormDataEntityExts.addAll(addList);
                if (removeSubPaymentSheet.size() > BasicConstant.ZERO) {
                    paasFormDataEntityExts.removeAll(removeSubPaymentSheet);
                }
                for (PaasFormDataEntityExt paasFormDataEntityExt : paasFormDataEntityExts) {
                    JSONObject data = paasFormDataEntityExt.getData();
                    if(data.get(PaymentSheetEnum.CUSTOMER_ID.getAttr()) instanceof  String){
                        customerArr.clear();
                        JSONObject object = new JSONObject();
                        object.put(BasicConstant.ID,FastJsonHelper.getLongOrDefaultFromFormData(data,PaymentSheetEnum.CUSTOMER_ID.getAttr(),0L));
                        object.put(BasicConstant.NAME,FastJsonHelper.getStringOrDefaultFromFormData(data,PaymentSheetEnum.CUSTOMER_NAME_LINK_TEXT.getAttr(),""));
                        customerArr.add(object);
                    }else {
                        customerArr = FastJsonHelper.getJsonArrOrDefaultFromFormData(data, PaymentSheetEnum.CUSTOMER_ID.getAttr(), jsonArray);
                    }
                    contractArr = data.getJSONArray(PaymentSheetEnum.CONTRACT.getAttr());
                    setAmountAndInvoiceAmountToContract(contractArr,contractIdSet);
                    JSONObject paymentSheetObj = new JSONObject();
                    paymentSheetObj.put(StringConstant.SAAS_LINK_BUSINESS_ID, paasFormDataEntityExt.getId());
                    paymentSheetObj.put(StringConstant.SAAS_LINK_BUSINESS_NAME, paasFormDataEntityExt.getSerialNo());
                    paymentSheetObj.put(InvoiceConstant.PAYMENT_SHEET_TYPE,data.getString(PaymentSheetEnum.PAYMENT_SHEET_TYPE.getAttr()));
                    paymentSheetArr.add(paymentSheetObj);
                    if(CollectionsUtil.isNotEmpty(contractArr)){
                        Long contractRefId = 0L;
                            if (contractArr.get(0) instanceof JSONObject) {
                                contractRefId = contractArr.getJSONObject(0).getLong(BasicConstant.ID);
                                String contractName = contractArr.getJSONObject(0).getString(BasicConstant.NAME);
                                JSONObject json = new JSONObject();
                                json.put(BasicConstant.ID,contractRefId);
                                json.put(BasicConstant.NAME,contractName);
                                copyContract.add(json);
                            } else {
                                contractRefId = data.getJSONArray(PaymentSheetEnum.CONTRACT.getAttr()).getLong(0);
                                String contractName = data.getJSONArray(PaymentSheetEnum.CONTRACT_LINK_TEXT.getAttr()).getString(0);
                                JSONObject json = new JSONObject();
                                json.put(BasicConstant.ID,contractRefId);
                                json.put(BasicConstant.NAME,contractName);
                                copyContract.add(json);
                            }
                            contractArr.clear();
                            contractArr.addAll(copyContract);
                            linkContractField.setDefaultAttr(saasUpdateHelp.getDefaultAttrPojo(contractArr));
                    }
                }
                linkCustomerField.setDefaultAttr(saasUpdateHelp.getDefaultAttrPojo(customerArr));
                linkPaymentSheetField.setDefaultAttr(saasUpdateHelp.getDefaultAttrPojo(paymentSheetArr));
                defaultAttrPoJo = new DefaultAttrPoJo();
                defaultAttrPoJo.setUseLinkValue(BasicConstant.ONE);
                jsonObject = new JSONObject();
                jsonObject.put("text",I18nMessageUtil.getMessage(PaymentRelationshipEnum.PAYMENT_SHEET.getAlias()));
                jsonObject.put("value",PaymentRelationshipEnum.PAYMENT_SHEET.getCode());
                defaultAttrPoJo.setLinkFormValue(jsonObject);
                linkPaymentRelationshipField.setDefaultAttr(defaultAttrPoJo);
                break;
            default:
                throw new XbbException(TemplateErrorCodeEnum.API_ERROR_350006);
        }
    }

    private void setAmountAndInvoiceAmountToContract(JSONArray contractArr,Set<Long> contractIdSet){
        if(CollectionsUtil.isNotEmpty(contractArr)) {
            for(int i = 0; i < contractArr.size(); i++) {
                Long contractRefId = 0L;

                if (contractArr.get(i) instanceof JSONObject) {
                    contractRefId = contractArr.getJSONObject(i).getLong(BasicConstant.ID);
                } else {
                    contractRefId = contractArr.getLong(i);
                }
                contractIdSet.add(contractRefId);
            }
        }
    }

    private void getContractObj(JSONArray contractArr,HandlerExplainBatchLinkItemDTO handlerExplainBatchLinkItemDTO,Set<Long> contractIdSet) throws XbbException{
        Map<String,Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        param.put(ParameterConstant.CORPID, handlerExplainBatchLinkItemDTO.getCorpid());
        param.put(ParameterConstant.ID_IN,contractIdSet);
        List<PaasFormDataEntityExt> contractList = paasEsModel.selectByCondition(XbbRefTypeEnum.CONTRACT.getCode(), new HashMap<>(BasicConstant.ONE), param, IndexTypeEnum.IDX_SAAS_CONTRACT);
        Map<Long,Double> contractAmountMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long,Double> contractInvoiceAmountMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        if(CollectionsUtil.isNotEmpty(contractList)) {
            for (PaasFormDataEntityExt paasFormDataEntityExt : contractList) {
                if(Objects.isNull(paasFormDataEntityExt.getData())){
                    continue;
                }
                contractAmountMap.put(paasFormDataEntityExt.getId(), paasFormDataEntityExt.getData().getDouble(ContractEnum.AMOUNT.getAttr()));
                contractInvoiceAmountMap.put(paasFormDataEntityExt.getId(),paasFormDataEntityExt.getData().getDouble(ContractEnum.INVOICE_AMOUNT.getAttr()));
            }
        }
        if(CollectionsUtil.isNotEmpty(contractArr)) {
            for (int i = 0;i < contractArr.size(); i++) {
                JSONObject contractObj = contractArr.getJSONObject(i);
                Long id = contractObj.getLong(BasicConstant.ID);
                contractObj.put(ContractEnum.AMOUNT.getAttr(), contractAmountMap.get(id));
                contractObj.put(ContractEnum.INVOICE_AMOUNT.getAttr(),contractInvoiceAmountMap.get(id));
            }
        }
    }
    /**
     * 校验单个开票是否符合要求
     *
     * @param xbbRefTypeEnum 类型
     * @param paasFormDataEntityExt 实体
     * @param jsonArray 数组
     * @param corpid 公司ID
     * @throws XbbException 异常
     */
    private void verifySingleData(XbbRefTypeEnum xbbRefTypeEnum, PaasFormDataEntityExt paasFormDataEntityExt, JSONArray jsonArray, String corpid,Map<String,List<PaasFormDataEntityExt>> paymentSheetMap,Map<Long,Double> contractIdToUnInvoiceAmountMap,Map<Long,Double> refIdToUnInvoiceAmountMap) throws XbbException{
        JSONObject data;
        Integer isRed;
        JSONArray customerArr;
        JSONArray contractArr;
        String status;
        Long contractId;
        Long customerId;
        Double unInvoiceAmount = 0D;
        Double contractUnInvoiceAmount = 0D;
        getContractIdToInvoiceAmountMap(xbbRefTypeEnum,Collections.singletonList(paasFormDataEntityExt),corpid,contractIdToUnInvoiceAmountMap,refIdToUnInvoiceAmountMap,paymentSheetMap);
        switch (xbbRefTypeEnum) {
            case CONTRACT:
                    data = paasFormDataEntityExt.getData();
                    customerArr = FastJsonHelper.getJsonArrOrDefaultFromFormData(data, ContractEnum.LINK_CUSTOMER.getAttr(), jsonArray);
                    if (customerArr.isEmpty()) {
                        throw new XbbException(SystemErrorCodeEnum.API_ERROR_100028, ErrorMessageConstant.CONTRACT_LINK_CUSTOMER);
                    }
                    customerId = customerArr.getJSONObject(BasicConstant.ZERO).getLong(StringConstant.SAAS_LINK_BUSINESS_ID);
                    if (Objects.isNull(customerId) || Objects.equals(customerId, 0L)) {
                        throw new XbbException(SystemErrorCodeEnum.API_ERROR_100028, ErrorMessageConstant.CONTRACT_LINK_CUSTOMER);
                    }
                    unInvoiceAmount = contractIdToUnInvoiceAmountMap.getOrDefault(paasFormDataEntityExt.getId(),0D);
                    if (unInvoiceAmount <= BasicConstant.ZERO_DOUBLE) {
                        throw new XbbException(InvoiceErrorCodeEnum.APT_ERROR_216001, ErrorMessageConstant.CONTRACT_SINGLE_ZERO_AMOUNT);
                    }
                break;
            case PAYMENT:
                    data = paasFormDataEntityExt.getData();
                    isRed = getIntegerOrDefaultFromFormData(paasFormDataEntityExt.getData(), PaymentEnum.IS_RED.getAttr(), BasicConstant.ZERO);
                    status = FastJsonHelper.getStringOrDefaultFromFormData(paasFormDataEntityExt.getData(), PaymentEnum.STATUS.getAttr(), PaymentStatusEnum.UN_RECEIVABLES.getCode());
                    boolean isBad = Objects.equals(status, PaymentStatusEnum.BAD_DEBT.getCode()) || Objects.equals(status, PaymentStatusEnum.PARTIAL_BAD_DEBT.getCode());
                    if (Objects.equals(isRed, BasicConstant.ONE) || isBad) {
                        throw new XbbException(InvoiceErrorCodeEnum.API_ERROR_216017);
                    }
                    customerArr = FastJsonHelper.getJsonArrOrDefaultFromFormData(data, PaymentEnum.CUSTOMER.getAttr(), jsonArray);
                    if(customerArr.isEmpty()){
                        throw new XbbException(SystemErrorCodeEnum.API_ERROR_100028, ErrorMessageConstant.CONTRACT_LINK_CUSTOMER);
                    }
                    contractArr = FastJsonHelper.getJsonArrOrDefaultFromFormData(data, PaymentEnum.CONTRACT.getAttr(), jsonArray);
                    if (contractArr.isEmpty()) {
                        throw new XbbException(SystemErrorCodeEnum.API_ERROR_100028, ErrorMessageConstant.CONTRACT_LINK_CUSTOMER);
                    }
                    contractId = contractArr.getJSONObject(BasicConstant.ZERO).getLong(StringConstant.SAAS_LINK_BUSINESS_ID);
                    if (Objects.isNull(contractId) || Objects.equals(contractId, 0L)) {
                        throw new XbbException(SystemErrorCodeEnum.API_ERROR_100028, ErrorMessageConstant.PAYMENT_LINK_CONTRACT);
                    }
                    contractUnInvoiceAmount = contractIdToUnInvoiceAmountMap.getOrDefault(contractId,0D);
                    if (contractUnInvoiceAmount <= BasicConstant.ZERO_DOUBLE) {
                        throw new XbbException(SystemErrorCodeEnum.API_ERROR_100028, ErrorMessageConstant.CONTRACT_SINGLE_ZERO_AMOUNT);
                    }
                    unInvoiceAmount = refIdToUnInvoiceAmountMap.getOrDefault(paasFormDataEntityExt.getId(),0D);
                    if (unInvoiceAmount <= BasicConstant.ZERO_DOUBLE) {
                        throw new XbbException(InvoiceErrorCodeEnum.APT_ERROR_216002, ErrorMessageConstant.PAYMENT_SINGLE_ZERO_AMOUNT);
                    }
                break;
            case PAYMENT_SHEET:
                    data = paasFormDataEntityExt.getData();
                    status = FastJsonHelper.getStringOrDefaultFromFormData(paasFormDataEntityExt.getData(), PaymentSheetEnum.PAYMENT_SHEET_TYPE.getAttr(), PaymentSheetTypeEnum.WRITE_OFF.getCode());
                    boolean isBadType = PaymentSheetTypeEnum.isBad(status);
                    boolean isRedType = PaymentSheetTypeEnum.isRed(status);
                    boolean isPrePaymentSheet = Objects.equals(status,PaymentSheetTypeEnum.PREPAYMENT.getCode()) || Objects.equals(status,PaymentSheetTypeEnum.RED_PREPAYMENT.getCode());
                    boolean isWriteOffPrePaymentSheet= Objects.equals(status,PaymentSheetTypeEnum.WRITE_OFF_PREPAYMENT.getCode());
                    if(isBadType || isRedType){
                        throw new XbbException(InvoiceErrorCodeEnum.API_ERROR_216017);
                    }
                    if(isWriteOffPrePaymentSheet){
                        throw new XbbException(InvoiceErrorCodeEnum.API_ERROR_216027);
                    }
                    customerArr = FastJsonHelper.getJsonArrOrDefaultFromFormData(data, PaymentSheetEnum.CUSTOMER_ID.getAttr(), jsonArray);
                    if(customerArr.isEmpty()){
                        if(isPrePaymentSheet){
                            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100028, ErrorMessageConstant.PAYMENT_SHEET_LINK_CUSTOMER);
                        }else {
                            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100028, ErrorMessageConstant.CONTRACT_LINK_CUSTOMER);
                        }
                    }
                    if(!isPrePaymentSheet){
                        contractArr = FastJsonHelper.getJsonArrOrDefaultFromFormData(data, PaymentSheetEnum.CONTRACT.getAttr(), jsonArray);
                        checkPaymentSheetRefContractInvoiceAmount(contractArr,contractIdToUnInvoiceAmountMap,false);
                        /*contractId = contractArr.getJSONObject(BasicConstant.ZERO).getLong(StringConstant.SAAS_LINK_BUSINESS_ID);
                        if (Objects.isNull(contractId) || Objects.equals(contractId, 0L)) {
                            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100028, ErrorMessageConstant.PAYMENT_SHEET_LINK_CONTRACT);
                        }
                        contractUnInvoiceAmount = contractIdToUnInvoiceAmountMap.getOrDefault(contractId,0D);
                        if (contractUnInvoiceAmount <= BasicConstant.ZERO_DOUBLE) {
                            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100028, ErrorMessageConstant.CONTRACT_SINGLE_ZERO_AMOUNT);
                        }*/

                    }
                    if(Objects.equals(paasFormDataEntityExt.getAlone(),SheetAloneEnum.PARENT.getCode())){
                        if(paymentSheetMap.containsKey(paasFormDataEntityExt.getUuid())){
                        List<PaasFormDataEntityExt> paasFormDataEntityExtList = paymentSheetMap.get(paasFormDataEntityExt.getUuid());
                        if(CollectionsUtil.isNotEmpty(paasFormDataEntityExtList)) {
                            for (PaasFormDataEntityExt paasFormData : paasFormDataEntityExtList) {
                                unInvoiceAmount =  Arith.add(unInvoiceAmount, refIdToUnInvoiceAmountMap.getOrDefault(paasFormData.getId(), 0D));
                            }
                        }
                    }
                    }else {
                        unInvoiceAmount = refIdToUnInvoiceAmountMap.getOrDefault(paasFormDataEntityExt.getId(),0D);
                    }
                    if (unInvoiceAmount <= BasicConstant.ZERO_DOUBLE){
                        throw new XbbException(InvoiceErrorCodeEnum.API_ERROR_216022, ErrorMessageConstant.PAYMENT_SHEET_SINGLE_ZERO＿AMOUNT);
                    }
                break;
            default:
                return;
        }
    }
    /**
     * 校验合并开票是否符合要求
     *
     * @param xbbRefTypeEnum 类型
     * @param paasFormDataEntityExts 实体
     * @param jsonArray 数组
     * @param corpid 公司ID
     * @throws XbbException 异常
     */
    private void verifyData(XbbRefTypeEnum xbbRefTypeEnum, List<PaasFormDataEntityExt> paasFormDataEntityExts, JSONArray jsonArray, String corpid,Map<String,List<PaasFormDataEntityExt>> paymentSheetMap,Map<Long,Double> contractIdToUnInvoiceAmountMap,Map<Long,Double> refIdToUnInvoiceAmountMap) throws XbbException{
        Long lastCustomerId = null;
        Double unInvoiceAmount = 0D;
        getContractIdToInvoiceAmountMap(xbbRefTypeEnum, paasFormDataEntityExts, corpid,contractIdToUnInvoiceAmountMap,refIdToUnInvoiceAmountMap,paymentSheetMap);
        if(Objects.equals(corpid,"dingc45df9402649cb4635c2f4657eb6378f")){
            LOG.warn("com.xbongbong.saas.service.impl.InvoiceServiceImpl.verifyData(),contractIdToUnInvoiceAmountMap:{},refIdToUnInvoiceAmountMap:{},paymentSheetMap:{}"
                    ,contractIdToUnInvoiceAmountMap,refIdToUnInvoiceAmountMap,paymentSheetMap);
        }
        switch (xbbRefTypeEnum) {
            case CONTRACT:
                for (PaasFormDataEntityExt paasFormDataEntityExt : paasFormDataEntityExts) {
                    JSONObject dataList = paasFormDataEntityExt.getData();
                    Integer isRed = getIntegerOrDefaultFromFormData(dataList, ContractEnum.IS_RED.getAttr(), BasicConstant.ZERO);
                    if (Objects.equals(isRed, BasicConstant.ONE)) {
                        throw new XbbException(InvoiceErrorCodeEnum.API_ERROR_216017);
                    }
                    JSONArray customerArr = FastJsonHelper.getJsonArrOrDefaultFromFormData(dataList, ContractEnum.LINK_CUSTOMER.getAttr(), jsonArray);
                    if (customerArr.isEmpty()) {
                        throw new XbbException(SystemErrorCodeEnum.API_ERROR_100028, ErrorMessageConstant.CONTRACT_LINK_CUSTOMER);
                    }
                    Long customerId = customerArr.getJSONObject(BasicConstant.ZERO).getLong(StringConstant.SAAS_LINK_BUSINESS_ID);
                    if (Objects.isNull(customerId) || Objects.equals(customerId, 0L)) {
                        throw new XbbException(SystemErrorCodeEnum.API_ERROR_100028, ErrorMessageConstant.CONTRACT_LINK_CUSTOMER);
                    }
                    if (Objects.nonNull(lastCustomerId) && !Objects.equals(lastCustomerId, customerId)) {
                        throw new XbbException(SystemErrorCodeEnum.API_ERROR_100028, ErrorMessageConstant.CONTRACT_INVOICE_MUST_SAME_CUSTOMER);
                    }
                    unInvoiceAmount = contractIdToUnInvoiceAmountMap.getOrDefault(paasFormDataEntityExt.getId(),0D);
                    if (unInvoiceAmount <= BasicConstant.ZERO_DOUBLE) {
                        throw new XbbException(InvoiceErrorCodeEnum.APT_ERROR_216001, ErrorMessageConstant.CONTRACT_BATCH_ZERO_AMOUNT);
                    }
                    lastCustomerId = customerId;
                }
                break;
            case PAYMENT:
                Long invoiceModelType = ModelTypeEnum.INVOICE.getCode();
                for (PaasFormDataEntityExt paasFormDataEntityExt : paasFormDataEntityExts) {
                    JSONObject dataList = paasFormDataEntityExt.getData();
                    Integer isRed = getIntegerOrDefaultFromFormData(paasFormDataEntityExt.getData(), PaymentEnum.RECEIVABLE_IS_RED.getAttr(), BasicConstant.ZERO);
                    String status = FastJsonHelper.getStringOrDefaultFromFormData(paasFormDataEntityExt.getData(), PaymentEnum.STATUS.getAttr(), PaymentStatusEnum.UN_RECEIVABLES.getCode());
                    boolean isBad = Objects.equals(status, PaymentStatusEnum.BAD_DEBT.getCode()) || Objects.equals(status, PaymentStatusEnum.PARTIAL_BAD_DEBT.getCode());
                    if (Objects.equals(isRed, BasicConstant.ONE) || isBad) {
                        throw new XbbException(InvoiceErrorCodeEnum.API_ERROR_216017);
                    }
                    JSONArray customerArr = FastJsonHelper.getJsonArrOrDefaultFromFormData(dataList, PaymentEnum.CUSTOMER.getAttr(), jsonArray);
                    JSONArray contractArr = FastJsonHelper.getJsonArrOrDefaultFromFormData(dataList, PaymentEnum.CONTRACT.getAttr(), jsonArray);
                    if (contractArr.isEmpty()) {
                        throw new XbbException(SystemErrorCodeEnum.API_ERROR_100028, ErrorMessageConstant.CONTRACT_LINK_CUSTOMER);
                    }
                    Long contractId = contractArr.getJSONObject(BasicConstant.ZERO).getLong(StringConstant.SAAS_LINK_BUSINESS_ID);
                    if (Objects.isNull(contractId) || Objects.equals(contractId, 0L)) {
                        throw new XbbException(SystemErrorCodeEnum.API_ERROR_100028, ErrorMessageConstant.PAYMENT_LINK_CONTRACT);
                    }
                    Double contractUnInvoiceAmount = contractIdToUnInvoiceAmountMap.getOrDefault(contractId,0D);
                    if (Objects.equals(contractUnInvoiceAmount,BasicConstant.ZERO_DOUBLE)) {
                        throw new XbbException(SystemErrorCodeEnum.API_ERROR_100028, ErrorMessageConstant.CONTRACT_BATCH_ZERO_AMOUNT);
                    }
                    Long customerId = customerArr.getJSONObject(BasicConstant.ZERO).getLong(StringConstant.SAAS_LINK_BUSINESS_ID);
                    if (Objects.nonNull(lastCustomerId) && !Objects.equals(lastCustomerId, customerId)) {
                        throw new XbbException(SystemErrorCodeEnum.API_ERROR_100028, ErrorMessageConstant.PAYMENT_INVOICE_MUST_SAME_CUSTOMER);
                    }
                    if (Objects.equals(paasFormDataEntityExt.getSysLong10(), invoiceModelType)) {
                        throw new XbbException(SystemErrorCodeEnum.API_ERROR_100028, ErrorMessageConstant.PAYMENT_INVOICE_MUST_NO_MODEL_INVOICE);
                    }
                    unInvoiceAmount = refIdToUnInvoiceAmountMap.getOrDefault(paasFormDataEntityExt.getId(),0D);
                    if (Objects.equals(unInvoiceAmount,BasicConstant.ZERO_DOUBLE)) {
                        throw new XbbException(InvoiceErrorCodeEnum.APT_ERROR_216002, ErrorMessageConstant.PAYMENT_BATCH_ZERO_AMOUNT);
                    }
                    lastCustomerId = customerId;
                }
                break;
            case PAYMENT_SHEET:
                int size = paasFormDataEntityExts.size();
                int isPrePaymentSheetSize = 0;
                boolean hasPrePaymentSheet = false;
                invoiceModelType = ModelTypeEnum.INVOICE.getCode();
                for(int i = 0;i < paasFormDataEntityExts.size();i++){
                    PaasFormDataEntityExt paasFormDataEntityExt = paasFormDataEntityExts.get(i);
                    JSONObject dataList = paasFormDataEntityExt.getData();
                    String status = FastJsonHelper.getStringOrDefaultFromFormData(paasFormDataEntityExt.getData(), PaymentSheetEnum.PAYMENT_SHEET_TYPE.getAttr(), PaymentSheetTypeEnum.WRITE_OFF.getCode());
                    boolean isBad = PaymentSheetTypeEnum.isBad(status);
                    boolean isRed = PaymentSheetTypeEnum.isRed(status);
                    boolean isPrePaymentSheet = Objects.equals(status,PaymentSheetTypeEnum.PREPAYMENT.getCode()) || Objects.equals(status,PaymentSheetTypeEnum.RED_PREPAYMENT.getCode());
                    boolean isWriteOffPrePaymentSheet= Objects.equals(status,PaymentSheetTypeEnum.WRITE_OFF_PREPAYMENT.getCode());
                    if(isRed || isBad){
                        throw new XbbException(InvoiceErrorCodeEnum.API_ERROR_216017);
                    }
                    if(isWriteOffPrePaymentSheet){
                        throw new XbbException(InvoiceErrorCodeEnum.API_ERROR_216027);
                    }
                    if(isPrePaymentSheet){
                        hasPrePaymentSheet = true;
                        isPrePaymentSheetSize++;
                    }
                    if(Objects.equals(i,size-1)){
                        if(hasPrePaymentSheet) {
                            if (isPrePaymentSheetSize != size) {
                                throw new XbbException(InvoiceErrorCodeEnum.API_ERROR_216053);
                            }
                        }
                    }
                    JSONArray customerArr = FastJsonHelper.getJsonArrOrDefaultFromFormData(dataList, PaymentSheetEnum.CUSTOMER_ID.getAttr(), jsonArray);
                    if(!isPrePaymentSheet){
                        JSONArray contractArr = FastJsonHelper.getJsonArrOrDefaultFromFormData(dataList, PaymentSheetEnum.CONTRACT.getAttr(), jsonArray);
                        checkPaymentSheetRefContractInvoiceAmount(contractArr,contractIdToUnInvoiceAmountMap,true);
                    }
                    Long customerId = customerArr.getJSONObject(BasicConstant.ZERO).getLong(StringConstant.SAAS_LINK_BUSINESS_ID);
                    if (Objects.nonNull(lastCustomerId) && !Objects.equals(lastCustomerId, customerId)) {
                        throw new XbbException(SystemErrorCodeEnum.API_ERROR_100028, ErrorMessageConstant.PAYMENT_SHEET_INVOICE_MUST_SAME_CUSTOMER);
                    }
                    if (Objects.equals(paasFormDataEntityExt.getSysLong10(), invoiceModelType)) {
                        throw new XbbException(SystemErrorCodeEnum.API_ERROR_100028, ErrorMessageConstant.PAYMENT_SHEET_INVOICE_MUST_NO_MODEL_INVOICE);
                    }
                    if(Objects.equals(paasFormDataEntityExt.getAlone(),SheetAloneEnum.PARENT.getCode())){
                        if(paymentSheetMap.containsKey(paasFormDataEntityExt.getUuid())){
                            List<PaasFormDataEntityExt> paasFormDataEntityExtList = paymentSheetMap.get(paasFormDataEntityExt.getUuid());
                            if(CollectionsUtil.isNotEmpty(paasFormDataEntityExtList)) {
                                for (PaasFormDataEntityExt paasFormData : paasFormDataEntityExtList) {
                                    unInvoiceAmount =  Arith.add(unInvoiceAmount, refIdToUnInvoiceAmountMap.getOrDefault(paasFormData.getId(), 0D));
                                }
                            }
                        }
                    }else {
                        unInvoiceAmount = refIdToUnInvoiceAmountMap.getOrDefault(paasFormDataEntityExt.getId(),0D);
                    }
                    if (Objects.equals(unInvoiceAmount,BasicConstant.ZERO_DOUBLE)) {
                        throw new XbbException(InvoiceErrorCodeEnum.API_ERROR_216022, ErrorMessageConstant.PAYMENT_SHEET_BATCH_ZERO_AMOUNT);
                    }
                    lastCustomerId = customerId;
                }
               break;
            default:
                throw new XbbException(TemplateErrorCodeEnum.API_ERROR_350006);
        }
    }

    private void checkPaymentSheetRefContractInvoiceAmount(JSONArray contractArr,Map<Long,Double> contractIdToUnInvoiceAmountMap,boolean isMerge) throws XbbException{
        if(CollectionsUtil.isNotEmpty(contractArr)){
            Integer invoiceZero = 0;
            for(int i=0;i<contractArr.size();i++){
                Long contractId = contractArr.getJSONObject(i).getLong(StringConstant.SAAS_LINK_BUSINESS_ID);
                if (Objects.isNull(contractId) || Objects.equals(contractId, 0L)) {
                    throw new XbbException(SystemErrorCodeEnum.API_ERROR_100028, ErrorMessageConstant.PAYMENT_SHEET_LINK_CONTRACT);
                }
                Double contractUnInvoiceAmount = contractIdToUnInvoiceAmountMap.getOrDefault(contractId, 0D);
                if (Objects.equals(contractUnInvoiceAmount, BasicConstant.ZERO_DOUBLE)) {
                    invoiceZero ++;
                }
            }
            if(Objects.equals(invoiceZero,contractArr.size())){
                if(isMerge) {
                    throw new XbbException(SystemErrorCodeEnum.API_ERROR_100028, ErrorMessageConstant.CONTRACT_BATCH_ZERO_AMOUNT);
                }else {
                    throw new XbbException(SystemErrorCodeEnum.API_ERROR_100028, ErrorMessageConstant.CONTRACT_SINGLE_ZERO_AMOUNT);
                }
            }
        }else {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100028, ErrorMessageConstant.PAYMENT_SHEET_LINK_CONTRACT);
        }
    }

    private void updateBatch(InvoiceUpdateBatchDTO invoiceUpdateBatchDTO) throws XbbException {
        try {
            String corpid = invoiceUpdateBatchDTO.getCorpid();
            List<UpdateDataEntity> updateList = new ArrayList<>();
            List<InvoiceUpdateDTO> returnedPurchaseList = invoiceUpdateBatchDTO.getInvoiceList();
            if (Objects.nonNull(returnedPurchaseList) && !returnedPurchaseList.isEmpty()) {
                returnedPurchaseList.forEach((item)->{
                    updateList.add(ExplainUtil.getUpdateData(item.getId(), item.getData(), corpid));
                });
            }
            if (!updateList.isEmpty()) {
                invoiceModel.updateBatch(updateList, corpid);
            }
        } catch (Exception e) {
            LOG.error("invoiceService.updateBatch 执行出错：", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
    }



    @Override
    public void afterSave(SaasFormSaveDTO saasFormSaveDTO) throws XbbException{
        boolean isNew = saasFormSaveDTO.getIsNew();
        boolean isRed = false;
        Integer isImport = saasFormSaveDTO.getIsImport();
        PaasFormDataEntity newPaasFormDataEntity = saasFormSaveDTO.getNewPaasFormDataEntity();
        Long invoiceId = newPaasFormDataEntity.getId();
        JSONObject newData = saasFormSaveDTO.getNewData();
        JSONObject oldData = saasFormSaveDTO.getOldData();
        if(newData.containsKey(InvoiceEnum.ORIGIN_ID.getAttr())){
            Long originId = FastJsonHelper.getLongOrDefaultFromFormData(newData,InvoiceEnum.ORIGIN_ID.getAttr(),0L);
            if(originId >0){
                isRed = true;
            }
        }
        String corpid = saasFormSaveDTO.getCorpid();
        boolean isEnable = false;
        Long originId = FastJsonHelper.getLongOrDefaultFromFormData(newData, InvoiceEnum.ORIGIN_ID.getAttr(), 0L);
        if(isNew) {
            //新增失败的发票es回滚，在外部insert内已处理（直接物理删除es）
            if (originId > BasicConstant.ZERO) {
                JSONObject jsonObject = new JSONObject();
                jsonObject.put(InvoiceEnum.HAS_RED.getAttr(), BasicConstant.ONE);
                UpdateDataEntity updateData = ExplainUtil.getUpdateData(originId, jsonObject, corpid);
                invoiceModel.updateBatch(Collections.singletonList(updateData), corpid);

                jsonObject = new JSONObject();
                jsonObject.put(InvoiceEnum.IS_RED.getAttr(), BasicConstant.ONE);
                UpdateDataEntity updateData1 = ExplainUtil.getUpdateData(invoiceId, jsonObject, corpid);
                invoiceModel.updateBatch(Collections.singletonList(updateData1), corpid);
            }
            /*Integer distributorMark = saasFormSaveDTO.getDistributorMark();
            if (Objects.equals(distributorMark, DistributorMarkEnum.DISTRIBUTOR.getCode())) {
                StartProcessDTO startProcessDTO = new StartProcessDTO();
                BeanUtil.copyProperties(saasFormSaveDTO, startProcessDTO);
                BeanUtil.copyProperties(newPaasFormDataEntity, startProcessDTO);
                startProcessDTO.setFormDataId(newPaasFormDataEntity.getId());
                startProcessDTO.setDistributorMark(distributorMark);
                startProcessDTO.setSaasMark(SaasMarkEnum.SAAS.getCode());
                StartProcessVO startProcessVO = postPositionProcessHelp.startProcess(startProcessDTO);
                if (Objects.equals(startProcessVO.getNoApprovalRequired(), 0)) {
                    // TODO 更新单据状态
                    InvoiceEntityExt invoiceEntity = new InvoiceEntityExt();
                    invoiceEntity.setCorpid(corpid);
                    invoiceEntity.setId(startProcessDTO.getFormDataId());
                    invoiceEntity.setFlowStatus(FlowStatusEnum.IN_APPROVAL.getType());
                    invoiceModel.update(invoiceEntity);
                }*//* else if (Objects.equals(startProcessVO.getNoApprovalRequired(), 2)) {
                    // TODO 执行删除逻辑
                }*//*
            }*/
        }
        SaasNeedRedundantAttrPojo saasNeedRedundantAttrPoJo = saasFormSaveDTO.getSaasNeedRedundantAttrPoJo();
        //审批的时候只能从 saasNeedPojo 拿
        if(CollectionsUtil.isNotEmpty(saasNeedRedundantAttrPoJo.getAmountDetail())){
            saasFormSaveDTO.setAmountDetail(saasNeedRedundantAttrPoJo.getAmountDetail());
        }
        if(CollectionsUtil.isEmpty(saasNeedRedundantAttrPoJo.getAmountDetail()) && Objects.equals(isImport,BasicConstant.ZERO)){
            //兼容老数据,老数据走导入的老逻辑
            isImport = BasicConstant.ONE;
        }
        Object contractNoObject = newData.get(InvoiceEnum.CONTRACT_ID_LINK_TEXT.getAttr());
        List<String> contractNoList = null;
        if(Objects.nonNull(contractNoObject)){
            if(contractNoObject instanceof String[]){
                String[]  purchaseNos = (String[]) contractNoObject;
                contractNoList = new ArrayList<>(Arrays.asList(purchaseNos));
            }else if(contractNoObject instanceof List){
                contractNoList = (List<String>) contractNoObject;
            }
        }else {
            contractNoList = new ArrayList<>();
        }
        InvoiceRelationshipEditPojo invoiceRelationshipEditPojo = getAddOrDeleteRelationship(newData,oldData,corpid,invoiceId);
        //开票的金额
        Double totalMoney = getDoubleOrDefaultFromFormData(newData, InvoiceEnum.TOTAL_MONEY.getAttr(), 0D);
        //-------------------------------关系表存储公共的属性
        Long now = (long) DateUtil.getInt();
        Long customerId = FastJsonHelper.getLongOrDefaultFromFormData(newData, InvoiceEnum.CUSTOMER_NAME.getAttr(), 0L);
        String customerName = FastJsonHelper.getStringOrDefaultFromFormData(newData, InvoiceEnum.CUSTOMER_NAME_LINK_TEXT.getAttr(), "");
        if(!isNew){
            // 删除原先的的合同和回款关系，以后再改成批量更新方式
            deleteInvoiceRelation(corpid, invoiceId);
        }
        // 2020 4/24 新增小功能 新建销项发票 客户没有填发票信息 和 寄送地址就 存到客户发票信息表 和 寄送表
        if(isNew){
            JSONArray customerInvoice =  FastJsonHelper.getJsonArrOrDefaultFromFormData(newData, InvoiceEnum.CUSTOMER_INVOICE.getAttr(),new JSONArray());
            JSONArray customerExpress =  FastJsonHelper.getJsonArrOrDefaultFromFormData(newData, InvoiceEnum.CUSTOMER_EXPRESS.getAttr(),new JSONArray());
            Map<String,Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            param.put("corpid",corpid);
            param.put("customerId",customerId);
            param.put("del",BasicConstant.ZERO);
            if(CollectionsUtil.isNotEmpty(customerInvoice)){
               Integer count = customerInvoiceModel.getEntitysCount(param);
               if(count <= BasicConstant.ZERO){
                   invoiceCommonHelper.saveCustomerInvoiceAndExpress(corpid,customerId,saasFormSaveDTO.getUserId(),saasFormSaveDTO.getLoginUserName(),customerInvoice,null);
               }
           }
           if(CollectionsUtil.isNotEmpty(customerExpress)){
               Integer count = customerExpressModel.getEntitysCount(param);
               if(count <= BasicConstant.ZERO){
                   invoiceCommonHelper.saveCustomerInvoiceAndExpress(corpid,customerId,saasFormSaveDTO.getUserId(),saasFormSaveDTO.getLoginUserName(),null,customerExpress);
               }
           }

            // 新建发票动态
            try {
                if (!Objects.equals(DistributorMarkEnum.DISTRIBUTOR.getCode(), saasFormSaveDTO.getDistributorMark())) {
                    DynamicStrategy dynamicStrategy = dynamicStrategyFactory.getDynamicStrategyByBusinessType(saasFormSaveDTO.getBusinessType());
                    transactionHelp.afterCommitOrCommitNow(p -> {
                        dynamicStrategy.save(DynamicSaveDTO.initDynamicSaveDTO(newPaasFormDataEntity.getId(), newPaasFormDataEntity.getFormId(), saasFormSaveDTO,
                                userModel.getByKey(newPaasFormDataEntity.getCreatorId(), corpid), null));
                    });
                }
            } catch (Exception e) {
                LOG.error("新建发票动态失败:", e);
            }
        }
        InvoiceCommonSavePojo invoiceCommonSavePojo = new InvoiceCommonSavePojo(invoiceRelationshipEditPojo.getContractIdList(),corpid,invoiceId,originId,now,saasNeedRedundantAttrPoJo,isNew,isEnable,isImport,isRed,totalMoney,saasFormSaveDTO.getAmountDetail(),newPaasFormDataEntity,saasFormSaveDTO.getLoginUser(),saasFormSaveDTO.getBusinessType(),saasFormSaveDTO.getSubBusinessType());
        boolean contractInvoiceFlag = saasNeedRedundantAttrPoJo.isHasContract() && !saasNeedRedundantAttrPoJo.isHasPayment() && !saasNeedRedundantAttrPoJo.isHasPaymentSheet();
        boolean paymentInvoiceFlag = saasNeedRedundantAttrPoJo.isHasPayment() && saasNeedRedundantAttrPoJo.isHasContract() && !saasNeedRedundantAttrPoJo.isHasPaymentSheet();
        boolean paymentSheetInvoiceFlag = saasNeedRedundantAttrPoJo.isHasPaymentSheet() && saasNeedRedundantAttrPoJo.isHasContract() && !saasNeedRedundantAttrPoJo.isHasPayment();
        boolean isPrePaymentSheetFlag = saasNeedRedundantAttrPoJo.isPrePaymentSheet();
        try {
            if(saasNeedRedundantAttrPoJo.isContractUnion() || contractInvoiceFlag) {
                //合同不为空 其他为空 合同合并开票
                invoiceCommonSavePojo.setRefIdList(invoiceRelationshipEditPojo.getContractIdList());
                invoiceCommonSavePojo.setRefTypeEnum(RefTypeEnum.CONTRACT);
                invoiceCommonSavePojo.setContractNos(contractNoList);
                invoiceCommonSavePojo.setCustomerId(customerId);
                invoiceCommonSavePojo.setCustomerName(customerName);
                invoiceCommonSaveHandle(invoiceCommonSavePojo);
            }else if(saasNeedRedundantAttrPoJo.isPaymentUnion() || paymentInvoiceFlag) {
                invoiceCommonSavePojo.setRefIdList(invoiceRelationshipEditPojo.getPaymentIdList());
                invoiceCommonSavePojo.setRefTypeEnum(RefTypeEnum.PAYMENT);
                invoiceCommonSavePojo.setContractNos(contractNoList);
                invoiceCommonSavePojo.setCustomerId(customerId);
                invoiceCommonSavePojo.setCustomerName(customerName);
                invoiceCommonSaveHandle(invoiceCommonSavePojo);
            }else if(saasNeedRedundantAttrPoJo.isPaymentSheetUnion() || paymentSheetInvoiceFlag || isPrePaymentSheetFlag) {
                invoiceCommonSavePojo.setRefIdList(invoiceRelationshipEditPojo.getPaymentSheetIdList());
                invoiceCommonSavePojo.setRefTypeEnum(RefTypeEnum.PAYMENTSHEET);
                invoiceCommonSavePojo.setContractNos(contractNoList);
                invoiceCommonSavePojo.setCustomerId(customerId);
                invoiceCommonSavePojo.setCustomerName(customerName);
                invoiceCommonSaveHandle(invoiceCommonSavePojo);
            }else {
                InvoiceRelationshipEntity invoiceRelationshipEntity = invoiceHelp.buildNewInvoiceRelation(false, invoiceId, now,customerId,customerName, corpid,totalMoney,0L,"",0L, "",0L, "",0);
                if (Objects.nonNull(invoiceRelationshipEntity)) {
                    try {
                        invoiceRelationshipModel.insert(invoiceRelationshipEntity);
                    } catch (Exception e) {
                        LOG.error("插入发票关系实体表出错", e);
                        throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
                    }
                }//消息推送
                invoiceHelp.invoiceMessagePushHandle(invoiceCommonSavePojo);
            }
        } catch (XbbException e) {
            rollBack4LinkEs(null, corpid, invoiceRelationshipEditPojo.getContractIdList(), invoiceRelationshipEditPojo.getPaymentIdList(), invoiceRelationshipEditPojo.getPaymentSheetIdList());
            LOG.error("invoiceServiceImp.afterSave 执行出错：", e);
            throw e;
        }catch (Exception e){
            rollBack4LinkEs(null, corpid, invoiceRelationshipEditPojo.getContractIdList(), invoiceRelationshipEditPojo.getPaymentIdList(), invoiceRelationshipEditPojo.getPaymentSheetIdList());
            LOG.error("invoiceServiceImp.afterSave 执行出错：", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
        if(isRed){
            List<PaasFormDataEntityExt> paasFormDataEntityExts = paymentService.getReceivablesBySourceIdIn(corpid, ModelTypeEnum.INVOICE.getXbbRefTypeEnum().getCode(), Collections.singletonList(originId));
            if(CollectionsUtil.isNotEmpty(paasFormDataEntityExts)){
                saasFormSaveDTO.setHasReceivables(BasicConstant.ONE);
            }
        }
        //获取当前处于什么模式
        Long modelType = fundSetService.getModelType(corpid,XbbRefTypeEnum.CRM);
        if(Objects.equals(modelType,ModelTypeEnum.INVOICE.getCode()) && isNew){
            if(!isRed) {
                JSONArray contractIdArray = newData.getJSONArray(InvoiceEnum.CONTRACT_ID.getAttr());
                if (CollectionsUtil.isNotEmpty(contractIdArray)) {
                    receivablesHelper.createReceivablesHandle(saasFormSaveDTO, modelType, null);
                }
            }
        }
    }

    @Override
    public void invoiceCommonSaveHandle(InvoiceCommonSavePojo invoiceCommonSavePojo)throws XbbException {
        boolean isEnable = invoiceCommonSavePojo.getIsEnable();
        Integer isImport = invoiceCommonSavePojo.getIsImport();
        boolean isRed = invoiceCommonSavePojo.getIsRed();
        boolean isPrePaymentSheet = invoiceCommonSavePojo.getSaasNeedRedundantAttrPoJo().isPrePaymentSheet();
        boolean isPrePaymentSheetUnion = invoiceCommonSavePojo.getSaasNeedRedundantAttrPoJo().isPrePaymentSheetUnion();
        String paymentNo = "";
        String paymentSheetNo = "";
        Long contractId = 0L;
        Long paymentId = 0L;
        Long paymentSheetId = 0L;
        List<Long> refIdList  = invoiceCommonSavePojo.getRefIdList();
        List<Long> parentIdList = invoiceCommonSavePojo.getParentRefIdList();
        RefTypeEnum refTypeEnum = invoiceCommonSavePojo.getRefTypeEnum();
        String corpid = invoiceCommonSavePojo.getCorpid();
        List<String> contractNos = invoiceCommonSavePojo.getContractNos();
        Map<Long,String> contractMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        if(CollectionsUtil.isNotEmpty(parentIdList)){
            for(int i =0;i<parentIdList.size();i++){
                Long id = parentIdList.get(i);
                String contractNo = contractNos.get(i);
                if(Objects.isNull(contractNo)){
                    contractNo = "";
                }
                contractMap.put(id,contractNo);
            }
        }
        Long invoiceId = invoiceCommonSavePojo.getInvoiceId();
        JSONArray amountDetail = invoiceCommonSavePojo.getAmountDetail();

        //获取金额明细里面合同或回款计划或回款的开票金额
        Map<Long,Double> subInvoiceMap = getInvoiceAmount(amountDetail,refTypeEnum,isPrePaymentSheet,isPrePaymentSheetUnion);
        int type = 0;
        Map<String, Object> amountMap;
        //这个map 给外层单次处理合同的开票数据用的
        Map<Long,Double> refContractInvoiceAmount = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<String,Double> refPaymentSheetInvoiceAmount = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        boolean isUnion = false;
        boolean isPrePaymentUnion = false;
        if (CollectionsUtil.isNotEmpty(refIdList)) {
            RefTypePojo refTypePojo = getRefType(refTypeEnum);
            if(Objects.nonNull(invoiceCommonSavePojo.getSaasNeedRedundantAttrPoJo())){
                switch (refTypePojo.getInvoiceEnum()) {
                    case CONTRACT_ID:
                        isUnion = invoiceCommonSavePojo.getSaasNeedRedundantAttrPoJo().isContractUnion();
                        if(isUnion){
                            type = 1;
                        }
                        break;
                    case PAYMENT_ID:
                        isUnion = invoiceCommonSavePojo.getSaasNeedRedundantAttrPoJo().isPaymentUnion();
                        if(isUnion){
                            type = 2;
                        }
                        break;
                    case PAYMENT_SHEET_ID:
                        isUnion = invoiceCommonSavePojo.getSaasNeedRedundantAttrPoJo().isPaymentSheetUnion();
                        //未来考虑 预收款回款单合并开票
                        isPrePaymentUnion = isUnion && isPrePaymentSheet;
                        if(isUnion){
                            type = 3;
                        }
                        if(isPrePaymentUnion){
                            isUnion = isPrePaymentSheetUnion;
                            type = 4;
                        }
                        break;
                    default:
                        throw new XbbException(InvoiceErrorCodeEnum.API_ERROR_216021);
                }
            }
            if(isRed){
                //红冲发票也存入关系表
                type = -1;
            }
            List<InvoiceRelationshipEntity> contractRelationList = new ArrayList<>();
            //获取该发票关联的合同 id对应的合同实体
            IndexTypeEnum indexTypeEnum = indexTypeModel.getIndexType(corpid, refTypePojo.getBusinessType(), SaasMarkEnum.SAAS.getCode());
            List<PaasFormDataEntityExt> entityExtList = paasEsModel.getByIdList(refIdList, corpid,SaasMarkEnum.SAAS.getCode(), refTypePojo.getBusinessType(), new ArrayList<>(), indexTypeEnum);
            Map<Long, PaasFormDataEntityExt> entityRefMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            entityExtList.forEach(entityExt -> entityRefMap.put(entityExt.getId(), entityExt));

            //获取除该发票外其他的关联了这个合同的关联信息 id 对应的关联信息
            Map<Long, List<InvoiceRelationshipEntity>> oldInvoiceMap = getInvoiceMap(corpid, invoiceId, refIdList,refTypePojo.getInvoiceEnum());
            for (int i = 0; i < refIdList.size(); i++) {
                Long refId = refIdList.get(i);
                String contractNo = "";
                //先将合同的编号进行处理回显
                double otherInvoiceSumAmount = 0D;
                //关联业务的实体（合同、应收款、回款单）
                PaasFormDataEntityExt paasFormDataEntityExt = entityRefMap.get(refId);
                if (Objects.isNull(paasFormDataEntityExt)) {
                    continue;
                }
                //获取以前开过票的关联实体
                List<InvoiceRelationshipEntity> relationInvoiceList = oldInvoiceMap.get(refId);
                //获取金额明细开票的金额
                double subInvoiceAmount = subInvoiceMap.getOrDefault(refId,0D);
                if (CollectionsUtil.isNotEmpty(relationInvoiceList)) {
                    for (InvoiceRelationshipEntity relationshipEntity : relationInvoiceList) {
                        //将以前关联过这个合同或应收款或回款单的发票的金额加起来
                        otherInvoiceSumAmount  = Arith.add(otherInvoiceSumAmount, relationshipEntity.getMoney());
                    }
                }
                JSONObject refData = paasFormDataEntityExt.getData();
                String subRefNo = paasFormDataEntityExt.getSerialNo();
                if(Objects.equals(refTypeEnum,RefTypeEnum.CONTRACT)){
                    contractId = refId;
                }else if(Objects.equals(refTypeEnum,RefTypeEnum.PAYMENT)){
                    contractId = refData.getLong(PaymentEnum.CONTRACT.getAttr());
                    paymentId = refId;
                    paymentNo = subRefNo;
                }else if(Objects.equals(refTypeEnum,RefTypeEnum.PAYMENTSHEET)){
                    if(!isPrePaymentSheet) {
                        contractId = refData.getJSONArray(PaymentSheetEnum.CONTRACT.getAttr()).getLong(0);
                    }
                    paymentSheetId = refId;
                    paymentSheetNo = subRefNo;
                }

                if(Objects.nonNull(contractMap.get(contractId))){
                    contractNo = contractMap.get(contractId);
                }else {
                    contractNo = "";
                }
                //关联实体的金额（如：合同的金额、回款计划的金额）开票不允许超过这个金额
                Double allMoney = getDoubleOrDefaultFromFormData(refData,refTypePojo.getAmountAttr(), 0D);
                //未开票金额
                double unInvoiceAmount;
                //已开票金额
                double invoiceAmount;
                if(!Objects.equals(isImport,BasicConstant.ONE)){
                        invoiceAmount = subInvoiceAmount;

                }else {
                    if(!isUnion){
                        //关联实体的金额（如：合同的金额、应收款的金额）开票不允许超过这个金额
                        if(Objects.isNull(invoiceCommonSavePojo.getTotalMoney())){
                            invoiceAmount = 0D;
                        }else {
                            invoiceAmount = invoiceCommonSavePojo.getTotalMoney();
                        }
                    }else {
                        invoiceAmount = allMoney;
                    }
                }
                //给外层的合同开票未开票金额使用
                saasSaveHelp.addMapNormal(refContractInvoiceAmount,contractId,invoiceAmount);
                double historyInvoiceAmount = otherInvoiceSumAmount + invoiceAmount;
                if(Objects.equals(refTypeEnum,RefTypeEnum.PAYMENTSHEET)){
                    //和删除 作废保持一致,更新 父回款单 需要查询所有的 子回款单历史
                    saasSaveHelp.addMapTwoInvoiceAmount(refPaymentSheetInvoiceAmount,paasFormDataEntityExt.getUuid(),invoiceAmount);
                }
                if(!Objects.equals(refTypeEnum,RefTypeEnum.CONTRACT)){
                    proUpdateHelp.update(refTypePojo.getBusinessType(), corpid,refId,refTypePojo.getInvoiceAmountAttr(),historyInvoiceAmount);
                }else {
                    //未开票=合同总额-已开
                    unInvoiceAmount =  Arith.sub(allMoney,historyInvoiceAmount);
                    JSONObject jsonObject = new JSONObject();
                    jsonObject.put(ContractEnum.UN_INVOICE_AMOUNT.getAttr(), unInvoiceAmount);
                    jsonObject.put(ContractEnum.INVOICE_AMOUNT.getAttr(), historyInvoiceAmount);
                    proUpdateHelp.update(refTypePojo.getBusinessType(), corpid, refId, jsonObject);
                }
                if (Objects.nonNull(invoiceAmount) && invoiceAmount == 0d) {
                    LOG.info("发票保存关系表有问题，参数1-corpid:{}, 参数2-amountDetail:{}, 参数3-refIdList:{}, 参数4-parentIdList:{}，参数5-refTypeEnum：{}, 参数6-subInvoiceMap:{}",
                            invoiceCommonSavePojo.getCorpid(), String.valueOf(amountDetail), refIdList, parentIdList, refTypeEnum, String.valueOf(subInvoiceMap));
                }
                InvoiceRelationshipEntity invoiceRelationshipEntity = invoiceHelp.buildNewInvoiceRelation(isEnable, invoiceId, invoiceCommonSavePojo.getNow(), invoiceCommonSavePojo.getCustomerId(), invoiceCommonSavePojo.getCustomerName(), corpid,invoiceAmount,contractId, contractNo, paymentId, paymentNo,paymentSheetId, paymentSheetNo, type);
                contractRelationList.add(invoiceRelationshipEntity);
            }
            if(Objects.equals(refTypeEnum,RefTypeEnum.PAYMENTSHEET)){
                //这里同步更新父回款单中 开票金额 为开票金额
                Set<String> uuidKey = refPaymentSheetInvoiceAmount.keySet();
                updateSumPaymentSheet(corpid,uuidKey,refTypePojo,refPaymentSheetInvoiceAmount,BasicConstant.ZERO,BasicConstant.ZERO);
            }
            if(Objects.equals(refTypeEnum,RefTypeEnum.PAYMENT) || Objects.equals(refTypeEnum,RefTypeEnum.PAYMENTSHEET)) {
                // 更新下关联合同的开票金额和未开票金额
                if(CollectionsUtil.isNotEmpty(parentIdList) && !isPrePaymentSheet) {
                    //除这个发票以外其他同样关联的发票开票金额
                    List<InvoiceRelationshipEntity> refInvoiceList = getRelationShipInvoice(invoiceId, corpid, parentIdList, InvoiceEnum.CONTRACT_ID);
                    Map<Long,Double> contractSubAmountMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                    Double otherContractInvoiceMoney = 0D;
                    Double contractSubInoviceAmount = 0D;
                    if (CollectionsUtil.isNotEmpty(refInvoiceList)) {
                        for (InvoiceRelationshipEntity relationshipEntity : refInvoiceList) {
                            otherContractInvoiceMoney = Arith.add(otherContractInvoiceMoney, relationshipEntity.getMoney());
                            contractSubAmountMap.put(relationshipEntity.getContractId(),contractSubAmountMap.getOrDefault(relationshipEntity.getContractId(),0D)+relationshipEntity.getMoney());
                        }
                    }
                    Map<String, Object> map = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                    map.put("idIn", parentIdList);
                    map.put(ParameterConstant.CORPID, corpid);
                    map.put(ParameterConstant.DEL, DelEnum.NORMAL.getDel());
                    List<ContractEntityExt> contractEntityExtList = contractModel.findEntitys(map);
                    if (CollectionsUtil.isNotEmpty(contractEntityExtList)) {
                        for (ContractEntityExt contractEntityExt : contractEntityExtList) {
                            Double contractAmount = getDoubleOrDefaultFromFormData(contractEntityExt.getData(), ContractEnum.AMOUNT.getAttr(), 0D);
                            Double parentContractInvoiceAmount = 0D;
                            //获取这次合同开票的总金额
                            parentContractInvoiceAmount = refContractInvoiceAmount.get(contractEntityExt.getId());
                            if (contractSubAmountMap.size() > 0) {
                                //当前合同已经 开过多少票
                                contractSubInoviceAmount = contractSubAmountMap.get(contractEntityExt.getId());
                            }
                            //关联合同的开票金额为其他已开票的合同金额 + 金额明细中属于这条合同的开票金额
                            if (contractSubInoviceAmount == null) {
                                contractSubInoviceAmount = 0D;
                            }
                            if (parentContractInvoiceAmount == null) {
                                parentContractInvoiceAmount = 0D;
                            }

                            JSONObject jsonObject = new JSONObject();
                            jsonObject.put(ContractEnum.INVOICE_AMOUNT.getAttr(), Arith.add(contractSubInoviceAmount, parentContractInvoiceAmount));
                            jsonObject.put(ContractEnum.UN_INVOICE_AMOUNT.getAttr(), Arith.sub(contractAmount, Arith.add(contractSubInoviceAmount, parentContractInvoiceAmount)));
                            UpdateDataEntity updateData = ExplainUtil.getUpdateData(contractEntityExt.getId(), jsonObject, corpid);
                            contractModel.updateBatch(Collections.singletonList(updateData), corpid);
                        }
                    }
                }
            }
            if (!contractRelationList.isEmpty()) {
                try {
                    invoiceRelationshipModel.batchInsert(contractRelationList);
                } catch (Exception e) {
                    LOG.error("插入发票关系实体表出错", e);
                    throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
                }
            }
        }
        invoiceHelp.invoiceMessagePushHandle(invoiceCommonSavePojo);
    }


    private void updateSumPaymentSheet(String corpid, Collection uuids,RefTypePojo refTypePojo,Map<String,Double> refPaymentSheetInvoiceAmount,Integer isCancel,Integer isDelete) throws XbbException{
        List<PaasFormDataEntityExt> paymentSheetEntityExtList = fundHelp.getParentAndChildEsDataListByUuids(IndexTypeEnum.IDX_SAAS_PAYMENT_SHEET, corpid, uuids);
        if(CollectionsUtil.isNotEmpty(paymentSheetEntityExtList)) {
            List<Long> subPaymentSheetIdList = new ArrayList<>();
            Map<Long,String> subUuidMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            Map<String, Long> uuidMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            Map<Long,Double> parentInvoiceMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            for(PaasFormDataEntityExt paymentSheetEntityExt : paymentSheetEntityExtList) {
                if(Objects.equals(paymentSheetEntityExt.getAlone(), SheetAloneEnum.CHILD.getCode())){
                    subUuidMap.put(paymentSheetEntityExt.getId(),paymentSheetEntityExt.getUuid());
                    subPaymentSheetIdList.add(paymentSheetEntityExt.getId());
                }
                if (Objects.equals(paymentSheetEntityExt.getAlone(), SheetAloneEnum.PARENT.getCode())) {
                    uuidMap.put(paymentSheetEntityExt.getUuid(), paymentSheetEntityExt.getId());
                }
            }
            Map<String,Object> map = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            map.put(InvoiceConstant.PAYMENT_SHEET_ID_IN,subPaymentSheetIdList);
            map.put("corpid",corpid);
            map.put("isCancel",BasicConstant.ZERO);
            map.put(InvoiceConstant.DEL,BasicConstant.ZERO);
            List<InvoiceRelationshipEntity> invoiceRelationshipEntities = invoiceRelationshipModel.findEntitys(map);
            for(InvoiceRelationshipEntity invoiceRelationshipEntity : invoiceRelationshipEntities){
                String uuid = subUuidMap.get(invoiceRelationshipEntity.getPaymentSheetId());
                saasSaveHelp.addMapNormal(parentInvoiceMap,uuidMap.getOrDefault(uuid,0L),invoiceRelationshipEntity.getMoney());
            }
            //如果是子回款单则需要其他子回款单的开票信息
            Iterator<Map.Entry<String, Long>> it = uuidMap.entrySet().iterator();
            while (it.hasNext()) {
                Map.Entry<String, Long> entry = it.next();
                String uuid = entry.getKey();
                Long parentId = entry.getValue();
                //父的回款单总开票金额
                double historyInvoiceAmount = parentInvoiceMap.getOrDefault(parentId,0D);
                //子的回款单这次的开票金额
                double subInvoiceParentSheetAmount = refPaymentSheetInvoiceAmount.get(uuid);

                if (Objects.equals(isCancel, 1) || Objects.equals(isDelete,BasicConstant.ONE)) {
                    //删除作废的时候子回款单这次作废删除的发票 这里删除 或 作废 已入库
                    proUpdateHelp.update(refTypePojo.getBusinessType(), corpid,parentId,refTypePojo.getInvoiceAmountAttr(),Arith.sub(historyInvoiceAmount,subInvoiceParentSheetAmount));
                } else {
                    //新增这里前面的金额明细还没有入库 所以这里直接取子的总开票金额
                    //新增时子回款单是历史所有开票金额 父现在的总开票金额 = 子历史开票金额 + 子总开票金额
                    proUpdateHelp.update(refTypePojo.getBusinessType(), corpid,parentId,refTypePojo.getInvoiceAmountAttr(),Arith.add(historyInvoiceAmount,subInvoiceParentSheetAmount));
                }
            }
        }
    }

    /**
     * 发票编辑时新增删除数据
     *  老的数据减去新的数据得到删除的关联数据,新的减去老的得到新增的关联数据
     * @param newData
     * @param oldData
     * @param corpid
     * @param invoiceId
     * @return
     * @throws XbbException
     */
    private InvoiceRelationshipEditPojo getAddOrDeleteRelationship(JSONObject newData, JSONObject oldData,String corpid,Long invoiceId)throws XbbException{
        // 老的
        List<Long> oldPaymentIdList = FastJsonHelper.getJsonArrOrDefaultFromFormData(oldData, InvoiceEnum.PAYMENT_ID.getAttr(), new JSONArray()).toJavaList(Long.class);
        List<Long> oldContractIdList = FastJsonHelper.getJsonArrOrDefaultFromFormData(oldData, InvoiceEnum.CONTRACT_ID.getAttr(), new JSONArray()).toJavaList(Long.class);
        //回款单的
        List<Long> oldPaymentSheetIdList = FastJsonHelper.getJsonArrOrDefaultFromFormData(oldData,InvoiceEnum.PAYMENT_SHEET_ID.getAttr(),new JSONArray()).toJavaList(Long.class);
        // 新的
        List<Long> paymentIdList = FastJsonHelper.getJsonArrOrDefaultFromFormData(newData, InvoiceEnum.PAYMENT_ID.getAttr(), new JSONArray()).toJavaList(Long.class);
        List<Long> contractIdList = FastJsonHelper.getJsonArrOrDefaultFromFormData(newData, InvoiceEnum.CONTRACT_ID.getAttr(), new JSONArray()).toJavaList(Long.class);
        //回款单的
        List<Long> paymentSheetIdList = FastJsonHelper.getJsonArrOrDefaultFromFormData(newData, InvoiceEnum.PAYMENT_SHEET_ID.getAttr(), new JSONArray()).toJavaList(Long.class);
        oldPaymentIdList.removeAll(paymentIdList);
        oldContractIdList.removeAll(contractIdList);
        oldPaymentSheetIdList.removeAll(paymentSheetIdList);
        //删掉减去的，并更新到对应的关联数据里
        invoiceEditAmountCompute(corpid,invoiceId,oldPaymentIdList,RefTypeEnum.PAYMENT);
        invoiceEditAmountCompute(corpid,invoiceId,oldContractIdList,RefTypeEnum.CONTRACT);
        invoiceEditAmountCompute(corpid,invoiceId,oldPaymentSheetIdList,RefTypeEnum.PAYMENTSHEET);
        return new InvoiceRelationshipEditPojo(oldPaymentIdList,oldContractIdList,oldPaymentSheetIdList,paymentIdList,contractIdList,paymentSheetIdList);
    }

    /**
     * 获取发票明细中开票的金额 组成一个id对应的map
     * @param amountDetail
     * @param refTypeEnum
     * @param isPrePaymentSheet 关联关系id对应的合同serialNo
     * @return
     */
    private Map<Long,Double> getInvoiceAmount(JSONArray amountDetail,RefTypeEnum refTypeEnum,boolean isPrePaymentSheet,boolean isPrePaymentSHeetUnion) {
        Map<Long,Double> map = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Long dataId = null;
        Double invoiceAmount;
        JSONObject contractObject = new JSONObject();
        if(CollectionsUtil.isNotEmpty(amountDetail)){
            for(int i=0;i<amountDetail.size();i++){
                JSONObject amountObject = amountDetail.getJSONObject(i);
                invoiceAmount = amountObject.getDouble(InvoiceConstant.INVOICE_AMOUNT);
                if(!isPrePaymentSheet && !isPrePaymentSHeetUnion) {
                    JSONArray contractRef = amountObject.getJSONArray(InvoiceConstant.CONTRACT);
                    if(CollectionsUtil.isNotEmpty(contractRef) && contractRef.size() > BasicConstant.ZERO){
                        contractObject = contractRef.getJSONObject(0);
                    }
                    if(Objects.nonNull(contractObject)){
                        dataId = contractObject.getLong(BasicConstant.ID);
                    }
                }
                if(Objects.equals(refTypeEnum,RefTypeEnum.PAYMENT)){
                    JSONArray paymentRef = amountObject.getJSONArray(InvoiceConstant.PAYMENT);
                    if(CollectionsUtil.isNotEmpty(paymentRef) && paymentRef.size() > BasicConstant.ZERO){
                        JSONObject paymentObject = paymentRef.getJSONObject(0);
                        if(Objects.nonNull(paymentObject)){
                            dataId = paymentObject.getLong(BasicConstant.ID);
                        }
                    }
                }else if(Objects.equals(refTypeEnum,RefTypeEnum.PAYMENTSHEET)){
                    JSONArray paymentSheetRef = amountObject.getJSONArray(InvoiceConstant.PAYMENTSHEET);
                    if(CollectionsUtil.isNotEmpty(paymentSheetRef) && paymentSheetRef.size() > BasicConstant.ZERO){
                        JSONObject paymentSheetObject = paymentSheetRef.getJSONObject(0);
                        if(Objects.nonNull(paymentSheetObject)){
                            dataId = paymentSheetObject.getLong(BasicConstant.ID);
                        }
                    }
                }
                if(dataId!=null){
                    map.put(dataId,invoiceAmount);
                }
            }
        }
        return map;
    }

    /**
     * 获取发票的关联类型pojo
     * @param refTypeEnum
     * @return
     * @throws XbbException
     */
    private RefTypePojo getRefType(RefTypeEnum refTypeEnum) throws XbbException{
        RefTypePojo refTypePojo = new RefTypePojo();
            switch (refTypeEnum){
                case CONTRACT:
                    refTypePojo.setBusinessType(XbbRefTypeEnum.CONTRACT.getCode());
                    refTypePojo.setInvoiceEnum(InvoiceEnum.CONTRACT_ID);
                    refTypePojo.setAmountAttr(ContractEnum.AMOUNT.getAttr());
                    refTypePojo.setInvoiceAmountAttr(ContractEnum.INVOICE_AMOUNT.getAttr());
                    break;
                case PAYMENT:
                    refTypePojo.setBusinessType(XbbRefTypeEnum.PAYMENT.getCode());
                    refTypePojo.setInvoiceEnum(InvoiceEnum.PAYMENT_ID);
                    refTypePojo.setAmountAttr(PaymentEnum.AMOUNT.getAttr());
                    refTypePojo.setInvoiceAmountAttr(PaymentEnum.INVOICE_AMOUNT.getAttr());
                    break;
                case PAYMENTSHEET:
                    refTypePojo.setBusinessType(XbbRefTypeEnum.PAYMENT_SHEET.getCode());
                    refTypePojo.setInvoiceEnum(InvoiceEnum.PAYMENT_SHEET_ID);
                    refTypePojo.setAmountAttr(PaymentSheetEnum.AMOUNT.getAttr());
                    refTypePojo.setInvoiceAmountAttr(PaymentSheetEnum.INVOICE_AMOUNT.getAttr());
                    break;
                default:
                    throw new XbbException(InvoiceErrorCodeEnum.API_ERROR_216021);
            }
            return refTypePojo;
        }

    /**
     * 发票编辑的时候老发票如果被删除可以先进行累加在从发票金额上减去
     * @param corpid 公司编号
     * @param invoiceId 发票id
     * @param idList 关联id 集合
     * @param refTypeEnum 关联的枚举类型
     * @throws XbbException
     */
    private void invoiceEditAmountCompute(String corpid,Long invoiceId,List<Long> idList,RefTypeEnum refTypeEnum) throws XbbException{
        if(CollectionsUtil.isEmpty(idList)){
            return;
        }
        RefTypePojo refTypePojo = getRefType(refTypeEnum);
        InvoiceEnum invoiceEnum = refTypePojo.getInvoiceEnum();
        Integer businessType = refTypePojo.getBusinessType();
        String attr = refTypePojo.getInvoiceAmountAttr();
        Map<Long, PaasFormDataEntityExt> contractMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            //获取除去减去的关联id对应关联实体的 map
            Map<Long, List<InvoiceRelationshipEntity>> oldInvoiceMap = getInvoiceMap(corpid, invoiceId, idList, invoiceEnum);
            if(Objects.equals(businessType,XbbRefTypeEnum.CONTRACT.getCode())){
                List<PaasFormDataEntityExt> contractList = paasEsModel.getByIdList(idList, corpid, SaasMarkEnum.SAAS.getCode(), businessType, new ArrayList<>(), IndexTypeEnum.IDX_SAAS_CONTRACT);
                contractList.forEach(contract-> contractMap.put(contract.getId(), contract));
            }
            for (Long id : idList) {
                List<InvoiceRelationshipEntity>  singleRelationInvoiceList = oldInvoiceMap.get(id);
                Double otherInvoiceSumAmount = 0D;
                if (CollectionsUtil.isNotEmpty(singleRelationInvoiceList)) {
                    for (InvoiceRelationshipEntity invoiceRelationshipEntity : singleRelationInvoiceList) {
                        otherInvoiceSumAmount = Arith.add(otherInvoiceSumAmount,invoiceRelationshipEntity.getMoney());
                    }
                }
                if(Objects.equals(businessType,XbbRefTypeEnum.CONTRACT.getCode())) {
                    if (Objects.nonNull(contractMap.get(id))) {
                        JSONObject jsonObject = new JSONObject();
                        jsonObject.put(ContractEnum.INVOICE_AMOUNT.getAttr(), otherInvoiceSumAmount);
                        Double amount = contractMap.get(id).getData().getDouble(ContractEnum.AMOUNT.getAttr());
                        jsonObject.put(ContractEnum.UN_INVOICE_AMOUNT.getAttr(), amount - otherInvoiceSumAmount);
                        proUpdateHelp.update(businessType, corpid, id, jsonObject);
                    }
                }else {
                    proUpdateHelp.update(businessType, corpid, id, attr, otherInvoiceSumAmount);
                }
            }
    }

    /**
     * 根据合同id/应收款id/回款单id 放入一个map 对应的值为开票的关联实体
     * @param corpid
     * @param invoiceId
     * @param oldRelationIdList
     * @param invoiceEnum
     * @return
     * @throws XbbException
     */
    private Map<Long, List<InvoiceRelationshipEntity>> getInvoiceMap(String corpid, Long invoiceId, List<Long> oldRelationIdList, InvoiceEnum invoiceEnum) throws XbbException {
        Map<Long, List<InvoiceRelationshipEntity>> oldInvoiceMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        List<InvoiceRelationshipEntity> relationList = getRelationShipInvoice(invoiceId, corpid, oldRelationIdList, invoiceEnum);
        relationList.forEach(relation -> {
            Long relationId = 0L;
            if (Objects.equals(invoiceEnum, InvoiceEnum.PAYMENT_ID)) {
                relationId = relation.getPaymentId();
            } else if (Objects.equals(invoiceEnum, InvoiceEnum.CONTRACT_ID)) {
                relationId = relation.getContractId();
            }else if(Objects.equals(invoiceEnum,InvoiceEnum.PAYMENT_SHEET_ID)){
                relationId = relation.getPaymentSheetId();
            }
            List<InvoiceRelationshipEntity> list = new ArrayList<>();
            if (oldInvoiceMap.containsKey(relationId)) {
                list = oldInvoiceMap.get(relationId);
            }
            list.add(relation);
            oldInvoiceMap.put(relationId, list);
        });
        return oldInvoiceMap;
    }

    public List<InvoiceRelationshipEntity> getRelationShipInvoice(Long invoiceId, String corpid, List<Long> relationIdList, InvoiceEnum invoiceEnum) throws XbbException {
        Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        param.put(ParameterConstant.CORPID, corpid);
        param.put(ParameterConstant.DEL, DelEnum.NORMAL.getDel());
        param.put(ParameterConstant.IS_CANCEL, 0);
        param.put("invoiceIdnot", invoiceId);
        if (Objects.equals(invoiceEnum, InvoiceEnum.CONTRACT_ID)) {
            param.put("contractIdIn", relationIdList);
        } else if (Objects.equals(invoiceEnum, InvoiceEnum.PAYMENT_ID)) {
            param.put("paymentIdIn", relationIdList);
        } else if(Objects.equals(invoiceEnum, InvoiceEnum.PAYMENT_SHEET_ID)){
            param.put("paymentSheetIdIn",relationIdList);
        }
        return invoiceRelationshipModel.findEntitys(param);
    }


    /**
     * 编辑时删除已存在的发票关系
     *
     * @param corpid    公司id
     * @param invoiceId 发票id
     */
    private void deleteInvoiceRelation(String corpid, Long invoiceId) {
        invoiceRelationshipModel.deleteByInvoiceId(invoiceId, corpid);
    }



    @Override
    public InvoiceUpdateByBusinessRuleVO updateFormDataByBusinessRule(InvoiceUpdateByBusinessRuleDTO invoiceUpdateByBusinessRuleDTO) throws XbbException {
        InvoiceUpdateByBusinessRuleVO invoiceUpdateByBusinessRuleVO = new InvoiceUpdateByBusinessRuleVO();
        try {
            String corpid = invoiceUpdateByBusinessRuleDTO.getCorpid();
            List<PaasFormDataEntityExt> formDataList = invoiceUpdateByBusinessRuleDTO.getFormDataList();
            List<UpdateDataEntity> updateList = ExplainUtil.getUpdateValueByBusinessRule(formDataList, corpid, invoiceUpdateByBusinessRuleDTO.getOperations());

            if (!updateList.isEmpty()) {
                invoiceModel.updateBatch(updateList, corpid);
                RuleBusinessLogDTO businessLogDTO = new RuleBusinessLogDTO();
                BeanUtil.copyProperties(invoiceUpdateByBusinessRuleDTO, businessLogDTO);
                businessLogDTO.setFormDataList(formDataList);
                ruleBusinessLogger.writeLog(businessLogDTO, updateList);
            }
        } catch (Exception e) {
            LOG.error("invoiceModel.updateFormDataByBusinessRule根据业务规则更新数据出错：", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
        return invoiceUpdateByBusinessRuleVO;
    }

    @Override
    public void updateInvoiceMoney(String corpid, InvoiceCancelOrRestorePojo invoiceCancelOrRestorePojo, Integer isCancel,Integer isDelete,Integer businessType) throws XbbException {
        List<PaasFormDataEntityExt> contractList = null;
        List<PaasFormDataEntityExt> paymentList = new ArrayList<>();
        List<PaasFormDataEntityExt> paymentSheetList = new ArrayList<>();
        if(!Objects.equals(businessType,XbbRefTypeEnum.CONTRACT.getCode())){
            if(Objects.equals(businessType,XbbRefTypeEnum.PAYMENT.getCode())){
                if(CollectionsUtil.isNotEmpty(invoiceCancelOrRestorePojo.getPaymentIdList())) {
                    paymentList = paasEsModel.getByIdList(invoiceCancelOrRestorePojo.getPaymentIdList(), corpid, SaasMarkEnum.SAAS.getCode(), XbbRefTypeEnum.PAYMENT.getCode(), new ArrayList<>(), IndexTypeEnum.IDX_SAAS_PAYMENT);
                    }
                }else if(Objects.equals(businessType,XbbRefTypeEnum.PAYMENT_SHEET.getCode())){
                    if(CollectionsUtil.isNotEmpty(invoiceCancelOrRestorePojo.getPaymentSheetIdList())) {
                        paymentSheetList = paasEsModel.getByIdList(invoiceCancelOrRestorePojo.getPaymentSheetIdList(), corpid, SaasMarkEnum.SAAS.getCode(), XbbRefTypeEnum.PAYMENT_SHEET.getCode(), new ArrayList<>(), IndexTypeEnum.IDX_SAAS_PAYMENT_SHEET);
                    }
                }
                if(CollectionsUtil.isNotEmpty(invoiceCancelOrRestorePojo.getContractIdList())) {
                    contractList = paasEsModel.getByIdList(invoiceCancelOrRestorePojo.getContractIdList(), corpid, SaasMarkEnum.SAAS.getCode(), XbbRefTypeEnum.CONTRACT.getCode(), new ArrayList<>(),IndexTypeEnum.IDX_SAAS_CONTRACT);
                }
            }else {
                if(CollectionsUtil.isNotEmpty(invoiceCancelOrRestorePojo.getContractIdList())) {
                    contractList = paasEsModel.getByIdList(invoiceCancelOrRestorePojo.getContractIdList(), corpid, SaasMarkEnum.SAAS.getCode(), XbbRefTypeEnum.CONTRACT.getCode(), new ArrayList<>(),IndexTypeEnum.IDX_SAAS_CONTRACT);
                }
            }
            List<PaasFormDataEntityExt> entityList = new ArrayList<>();
            RefTypePojo refTypePojo = new RefTypePojo();
            if(CollectionsUtil.isNotEmpty(paymentList)){
                entityList = paymentList;
                refTypePojo = getRefType(RefTypeEnum.PAYMENT);
            }else if(CollectionsUtil.isNotEmpty(paymentSheetList)){
                refTypePojo = getRefType(RefTypeEnum.PAYMENTSHEET);
                entityList = paymentSheetList;
            }
            Map<String,Double> subPaymentSheetMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            for (PaasFormDataEntityExt entityExt : entityList) {
                updateContractOrPaymentOrSheetIsCancel(entityExt, isCancel,isDelete,corpid, invoiceCancelOrRestorePojo, refTypePojo,subPaymentSheetMap);
            }
            //如果是回款单还需要更新父回款单
            if(Objects.equals(refTypePojo.getInvoiceEnum(),InvoiceEnum.PAYMENT_SHEET_ID)){
                Set<String> uuidKey = subPaymentSheetMap.keySet();
                updateSumPaymentSheet(corpid,uuidKey,refTypePojo,subPaymentSheetMap,isCancel,isDelete);
            }
            if(CollectionsUtil.isNotEmpty(contractList)){
                refTypePojo = getRefType(RefTypeEnum.CONTRACT);
                for (PaasFormDataEntityExt entityExt : contractList) {
                    updateContractOrPaymentOrSheetIsCancel(entityExt,isCancel,isDelete,corpid,invoiceCancelOrRestorePojo,refTypePojo,null);
                }
            }
        }

    private void updateContractOrPaymentOrSheetIsCancel(PaasFormDataEntityExt entity,Integer isCancel,Integer isDelete,String corpid,InvoiceCancelOrRestorePojo invoiceCancelOrRestorePojo,RefTypePojo refTypePojo,Map<String,Double> subPaymentSheetMap) throws XbbException{
        if(Objects.equals(refTypePojo.getInvoiceEnum(),InvoiceEnum.PAYMENT_ID) || Objects.equals(refTypePojo.getInvoiceEnum(),InvoiceEnum.PAYMENT_SHEET_ID)) {
            Map<Long,Double> refMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            if(Objects.equals(refTypePojo.getInvoiceEnum(),InvoiceEnum.PAYMENT_ID)){
                refMap = invoiceCancelOrRestorePojo.getPaymentRefMap();
            }else if(Objects.equals(refTypePojo.getInvoiceEnum(),InvoiceEnum.PAYMENT_SHEET_ID)){
                refMap = invoiceCancelOrRestorePojo.getPaymentSheetRefMap();
            }
            //这一次被新建 删除/作废的开票金额
            Double invoiceAmount = refMap.getOrDefault(entity.getId(),0D);
            if (Objects.equals(isCancel, 1) || Objects.equals(isDelete,BasicConstant.ONE)) {
                //应收款或回款单开的发票 减去这次开的
                double historyInvoiceAmount = Arith.sub(getDoubleOrDefaultFromFormData(entity.getData(), refTypePojo.getInvoiceAmountAttr(), 0D), invoiceAmount);
                proUpdateHelp.update(refTypePojo.getBusinessType(), corpid, entity.getId(),refTypePojo.getInvoiceAmountAttr(),historyInvoiceAmount);
                if(Objects.equals(refTypePojo.getInvoiceEnum(),InvoiceEnum.PAYMENT_SHEET_ID) && Objects.equals(entity.getAlone(),SheetAloneEnum.CHILD.getCode())) {
                    saasSaveHelp.addMapTwoInvoiceAmount(subPaymentSheetMap, entity.getUuid(),invoiceAmount);
                }
            } else {
                double historyInvoiceAmount = Arith.add(getDoubleOrDefaultFromFormData(entity.getData(), refTypePojo.getInvoiceAmountAttr(), 0D),invoiceAmount);
                proUpdateHelp.update(refTypePojo.getBusinessType(), corpid, entity.getId(),refTypePojo.getInvoiceAmountAttr(),historyInvoiceAmount);
                if(Objects.equals(refTypePojo.getInvoiceEnum(),InvoiceEnum.PAYMENT_SHEET_ID) && Objects.equals(entity.getAlone(),SheetAloneEnum.CHILD.getCode())) {
                    saasSaveHelp.addMapTwoInvoiceAmount(subPaymentSheetMap, entity.getUuid(),invoiceAmount);
                }
            }
        }
        if(Objects.equals(refTypePojo.getInvoiceEnum(),InvoiceEnum.CONTRACT_ID)) {
            //合同逻辑不一样 合同有两个应收款出自同一合同
            JSONObject jsonObject = new JSONObject();
            Map<Long,Double> contractInvoiceMap = invoiceCancelOrRestorePojo.getContractMap();
            Double contractInvoiceMoney = contractInvoiceMap.getOrDefault(entity.getId(),0D);
            if (Objects.equals(isCancel, BasicConstant.ONE) || Objects.equals(isDelete,BasicConstant.ONE)) {
                //这个次发票相关关联明细,这次开的金额作废,所以合同开票金额= 合同开票金额 - 这次开的金额
                jsonObject.put(refTypePojo.getInvoiceAmountAttr(), Arith.sub(getDoubleOrDefaultFromFormData(entity.getData(), refTypePojo.getInvoiceAmountAttr(), 0D),contractInvoiceMoney));
                jsonObject.put(ContractEnum.UN_INVOICE_AMOUNT.getAttr(), Arith.add(getDoubleOrDefaultFromFormData(entity.getData(), ContractEnum.UN_INVOICE_AMOUNT.getAttr(), 0D), contractInvoiceMoney));
            } else {
                jsonObject.put(refTypePojo.getInvoiceAmountAttr(), Arith.add(getDoubleOrDefaultFromFormData(entity.getData(), refTypePojo.getInvoiceAmountAttr(), 0D), contractInvoiceMoney));
                jsonObject.put(ContractEnum.UN_INVOICE_AMOUNT.getAttr(), Arith.sub(getDoubleOrDefaultFromFormData(entity.getData(), ContractEnum.UN_INVOICE_AMOUNT.getAttr(), 0D), contractInvoiceMoney));
            }
            proUpdateHelp.update(refTypePojo.getBusinessType(),corpid,entity.getId(),jsonObject);
        }
    }


    @Override
    public void dataConsistencyUpdate(String corpid, Long customerId, String customerName, String attr, String nameAttr) throws XbbException {
        try {
            BoolQueryBuilder filter = boolQuery()
                    .filter(termQuery("corpid.keyword", corpid))
                    .filter(termQuery("del", 0))
                    .filter(termQuery("data." + attr + ".keyword", customerId));
            List<String> fieldList = new ArrayList<>();
            fieldList.add(FieldTypeEnum.DATAID.getAlias());
            List<PaasFormDataEntityExt> esEntities = esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_INVOICE, filter, PaasFormDataEntityExt.class, fieldList);
            Set<Long> ids = new HashSet<>();
            for (PaasFormDataEntityExt esEntity : esEntities) {
                ids.add(esEntity.getDataId());
            }
            Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            param.put("corpid", corpid);
            param.put("idIn", ids);
            param.put("del", 0);
            List<InvoiceEntityExt> invoiceEntityExtList = invoiceModel.findEntitys(param);

            if (Objects.nonNull(invoiceEntityExtList) && !invoiceEntityExtList.isEmpty()) {
                List<InvoiceUpdateDTO> invoiceUpdateDTOList = new ArrayList<>();
                for (InvoiceEntityExt entityExt : invoiceEntityExtList) {
                    InvoiceUpdateDTO invoiceUpdateDTO = new InvoiceUpdateDTO();
                    invoiceUpdateDTO.setId(entityExt.getId());
                    JSONObject data = new JSONObject();
                    data.put(nameAttr, customerName);
                    invoiceUpdateDTO.setData(data);
                    invoiceUpdateDTOList.add(invoiceUpdateDTO);
                }
                InvoiceUpdateBatchDTO invoiceUpdateBatchDTO = new InvoiceUpdateBatchDTO();
                invoiceUpdateBatchDTO.setCorpid(corpid);
                invoiceUpdateBatchDTO.setInvoiceList(invoiceUpdateDTOList);
                updateBatch(invoiceUpdateBatchDTO);
            }

        } catch (Exception e) {
            LOG.error("InvoiceServiceImpl.dataConsistencyUpdateCustomer 出错，corpid=" + corpid + "  nameAttr=" + nameAttr + " attr=" + attr, e);
        }
    }

    @Override
    public void dataConsistencyUpdateContract(String corpid, Long contractId, String serialNo) throws XbbException {
        try {
            BoolQueryBuilder filter = boolQuery()
                    .filter(termQuery("corpid.keyword", corpid))
                    .filter(termQuery("del", 0))
                    .filter(termQuery(InvoiceEnum.getEsAttr4Keyword(InvoiceEnum.CONTRACT_ID), contractId));
            List<String> fieldList = new ArrayList<>();
            fieldList.add(FieldTypeEnum.DATAID.getAlias());
            List<PaasFormDataEntityExt> esEntities = esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_INVOICE, filter, PaasFormDataEntityExt.class, fieldList);
            Set<Long> ids = new HashSet<>();
            for (PaasFormDataEntityExt esEntity : esEntities) {
                ids.add(esEntity.getDataId());
            }
            Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            param.put("corpid", corpid);
            param.put("idIn", ids);
            param.put("del", 0);
            List<InvoiceEntityExt> invoiceEntityExtList = invoiceModel.findEntitys(param);
            if (Objects.nonNull(invoiceEntityExtList) && !invoiceEntityExtList.isEmpty()) {
                List<InvoiceUpdateDTO> invoiceUpdateDTOList = new ArrayList<>();
                for (InvoiceEntityExt entityExt : invoiceEntityExtList) {
                    JSONObject oldData = entityExt.getData();
                    if (oldData == null) {
                        continue;
                    }
                    List<Long> idList = FastJsonHelper.getJsonArrOrDefaultFromFormData(oldData, InvoiceEnum.CONTRACT_ID.getAttr(), new JSONArray()).toJavaList(Long.class);
                    List<String> noList = FastJsonHelper.getJsonArrOrDefaultFromFormData(oldData, InvoiceEnum.CONTRACT_ID_LINK_TEXT.getAttr(), new JSONArray()).toJavaList(String.class);
                    for (int i = 0; i < idList.size(); i++) {
                        Long cid = idList.get(i);
                        if (Objects.equals(cid, contractId)) {
                            noList.set(i, serialNo);
                        }
                    }

                    InvoiceUpdateDTO invoiceUpdateDTO = new InvoiceUpdateDTO();
                    invoiceUpdateDTO.setId(entityExt.getId());
                    JSONObject data = new JSONObject();
                    data.put(InvoiceEnum.CONTRACT_ID_LINK_TEXT.getAttr(), noList);
                    invoiceUpdateDTO.setData(data);
                    invoiceUpdateDTOList.add(invoiceUpdateDTO);
                }
                InvoiceUpdateBatchDTO invoiceUpdateBatchDTO = new InvoiceUpdateBatchDTO();
                invoiceUpdateBatchDTO.setCorpid(corpid);
                invoiceUpdateBatchDTO.setInvoiceList(invoiceUpdateDTOList);
                updateBatch(invoiceUpdateBatchDTO);
            }
        } catch (Exception e) {
            LOG.error("InvoiceServiceImpl.dataConsistencyUpdateContract fail， corpid=" + corpid + " contractId=" + contractId + "  contractNo=" + serialNo, e);
        }
    }

    @Override
    public void dataConsistencyUpdatePayment(String corpid, Long paymentId, String serialNo) throws XbbException {
        try {
            BoolQueryBuilder filter = boolQuery()
                    .filter(termQuery("corpid.keyword", corpid))
                    .filter(termQuery("del", 0))
                    .filter(termQuery(InvoiceEnum.getEsAttr4Keyword(InvoiceEnum.PAYMENT_ID), paymentId));
            List<String> fieldList = new ArrayList<>();
            fieldList.add(FieldTypeEnum.DATAID.getAlias());
            List<PaasFormDataEntityExt> esEntities = esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_INVOICE, filter, PaasFormDataEntityExt.class, fieldList);
            Set<Long> ids = new HashSet<>();
            for (PaasFormDataEntityExt esEntity : esEntities) {
                ids.add(esEntity.getDataId());
            }
            Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            param.put("corpid", corpid);
            param.put("idIn", ids);
            param.put("del", 0);
            List<InvoiceEntityExt> invoiceEntityExtList = invoiceModel.findEntitys(param);
            if (Objects.nonNull(invoiceEntityExtList) && !invoiceEntityExtList.isEmpty()) {
                List<InvoiceUpdateDTO> invoiceUpdateDTOList = new ArrayList<>();
                for (InvoiceEntityExt entityExt : invoiceEntityExtList) {
                    JSONObject oldData = entityExt.getData();
                    if (oldData == null) {
                        continue;
                    }
                    List<Long> idList = FastJsonHelper.getJsonArrOrDefaultFromFormData(oldData, InvoiceEnum.PAYMENT_ID.getAttr(), new JSONArray()).toJavaList(Long.class);
                    List<String> noList = FastJsonHelper.getJsonArrOrDefaultFromFormData(oldData, InvoiceEnum.PAYMENT_ID_LINK_TEXT.getAttr(), new JSONArray()).toJavaList(String.class);
                    for (int i = 0; i < idList.size(); i++) {
                        Long cid = idList.get(i);
                        if (Objects.equals(cid, paymentId)) {
                            noList.set(i, serialNo);
                        }
                    }

                    InvoiceUpdateDTO invoiceUpdateDTO = new InvoiceUpdateDTO();
                    invoiceUpdateDTO.setId(entityExt.getId());
                    JSONObject data = new JSONObject();
                    data.put(InvoiceEnum.PAYMENT_ID_LINK_TEXT.getAttr(), noList);
                    invoiceUpdateDTO.setData(data);
                    invoiceUpdateDTOList.add(invoiceUpdateDTO);
                }
                InvoiceUpdateBatchDTO invoiceUpdateBatchDTO = new InvoiceUpdateBatchDTO();
                invoiceUpdateBatchDTO.setCorpid(corpid);
                invoiceUpdateBatchDTO.setInvoiceList(invoiceUpdateDTOList);
                updateBatch(invoiceUpdateBatchDTO);
            }
        } catch (Exception e) {
            LOG.error("InvoiceServiceImpl.dataConsistencyUpdatePayment fail， corpid=" + corpid + " paymentId=" + paymentId + "  paymentNo=" + serialNo, e);
        }
    }

    @Override
    public void updateRollback(List<Long> idIn, String corpid) throws XbbException {
        if (Objects.isNull(idIn) || idIn.isEmpty()) {
            return;
        }
        Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        param.put("idIn", idIn);
        param.put(StringConstant.CORPID, corpid);
        List<InvoiceEntityExt> invoiceList = invoiceModel.findEntitysWithoutSub(param);
        if (Objects.nonNull(invoiceList)) {
            for (InvoiceEntityExt item : invoiceList) {
                PaasFormDataEntity paasFormDataEntity = new PaasFormDataEntity();
                BeanUtil.copyProperties(item, paasFormDataEntity);
                proEsHelper.reductionEsInUpdate(paasFormDataEntity, item.getId(), corpid, IndexTypeEnum.IDX_SAAS_INVOICE);
            }
        }
    }

    /**
     * 数据还原
     * @param corpid
     * @param customerUpdateTimeMap
     * @return
     * @throws
     * @author xingxing.xiao
     * @date 2019/09/18 09:24
     */
    @Override
    public void restoreBatch(String corpid, Map<Long, Long> customerUpdateTimeMap, CustomerRestoreBatchDTO customerRestoreBatchDTO) throws XbbException {
        try {
            // 根据客户的 id 和 updateTime 来查询要还原的数据
            List<Long> dataIdList = new ArrayList<>();
            List<String> serialNoList = new ArrayList<>();
            BoolQueryBuilder booleanQuery = boolQuery();
            booleanQuery.filter(termQuery(StringConstant.CORPID + StringConstant.POINT + StringConstant.KEY_WORD, corpid));
            booleanQuery.filter(termQuery(StringConstant.DEL, DelEnum.DELETE.getDel()));
            for (Map.Entry<Long, Long> entry : customerUpdateTimeMap.entrySet()) {
                BoolQueryBuilder shouldQueryBuilder = boolQuery();
                shouldQueryBuilder.filter(termsQuery(InvoiceEnum.getEsAttr4Keyword(InvoiceEnum.CUSTOMER_NAME), entry.getKey().toString()));
                shouldQueryBuilder.filter(rangeQuery(InvoiceEnum.UPDATE_TIME.getAttr()).gte(entry.getValue()));
                booleanQuery.should(shouldQueryBuilder);
            }
            booleanQuery.minimumShouldMatch(MINI_MUM_SHOULD_MATCH);
            List<String> fieldList = new ArrayList<>();
            fieldList.add(StringConstant.SAAS_LINK_BUSINESS_ID);
            fieldList.add(BasicConstant.SERIAL_NO);
            List<PaasFormDataEntityExt> paasFormDataEntityExtList = esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_INVOICE, booleanQuery, PaasFormDataEntityExt.class, fieldList);
            paasFormDataEntityExtList.forEach(item -> {
                dataIdList.add(item.getId());
                serialNoList.add(item.getSerialNo());
            });
            if (dataIdList.isEmpty()) {
                return;
            }
            invoiceModel.restoreBatch(dataIdList, corpid, DelEnum.NORMAL.getDel());
            // 日志
            OperateTypeEnum operateTypeEnum = OperateTypeEnum.REVERT_CANCEL;
            String nameStr = StringUtils.join(serialNoList, "，");
            String userName = customerRestoreBatchDTO.getLoginUserName();
            String userId = customerRestoreBatchDTO.getUserId();
            if(dataIdList.size() > 1){
                String memo = String.format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_USER_ARCHIVE_FORM_DATA), userName, operateTypeEnum.getName(), nameStr);
                List<InfoArrPojo> infoArrPojoList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                InfoArrPojo infoArrPojo = new InfoArrPojo();
                infoArrPojo.setTitle(XbbRefTypeEnum.INVOICE.getName());
                infoArrPojo.setContent(nameStr);
                infoArrPojoList.add(infoArrPojo);
                mongoLogHelp.buildLog4InfoArr(infoArrPojoList, corpid, userId, userName, OperateModuleTypeEnum.INVOICE, operateTypeEnum,
                        "", "", memo, customerRestoreBatchDTO.getHttpHeader());
            } else if(Objects.equals(dataIdList.size(), 1)){
                String memo = String.format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_USER_ARCHIVE_FORM_DATA), userName, operateTypeEnum.getName(), nameStr);
                mongoLogHelp.buildLog(corpid, userId, userName, OperateModuleTypeEnum.INVOICE, operateTypeEnum,
                        dataIdList.get(0).toString(), nameStr, memo, customerRestoreBatchDTO.getHttpHeader());
            }
        } catch (Exception e){
            LOG.error("InvoiceServiceImpl.restoreBatch 执行出错：", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
    }
    @Override
    public InvoiceGetByCustomerVO getByContract(InvoiceGetByContractDTO invoiceGetByContractDTO) throws XbbException {
        Long contractId = invoiceGetByContractDTO.getContractId();
        String corpid = invoiceGetByContractDTO.getCorpid();
        List<Long> contractIds = new ArrayList<>();
        List<Long> invoiceIds = new ArrayList<>();
        contractIds.add(contractId);
        InvoiceGetByCustomerVO invoiceGetByCustomerVO = new InvoiceGetByCustomerVO();
        UserVO userVo = invoiceGetByContractDTO.getLoginUser();
        Set<String> permSet = userVo.getPermSet();
        int total = 0;
        List<PaasFormDataEntityExt> results = new ArrayList<>();
        if(permSet.contains(ProPermissionAliasEnum.INVOICE_VIEW.getAlias())) {
            //根据合同ID获取正常发票列表
            XbbAggregatedPage<PaasFormDataEntityExt> esEntities = getNormalInvoiceListByEs(corpid, contractIds, invoiceGetByContractDTO);
            results = esEntities.getContent();
            results.forEach(e -> invoiceIds.add(e.getDataId()));
            //根据发票ID获取发票已红冲金额(负数)
            Map<Long, Double> redTotalMoneyByIdMap = getRedTotalMoneyByIdIn(invoiceIds, new ArrayList<>(), corpid);
            Iterator<PaasFormDataEntityExt> iterator = esEntities.getContent().iterator();
            while (iterator.hasNext()){
                PaasFormDataEntityExt paasFormDataEntityExt = iterator.next();
                Long dataId = paasFormDataEntityExt.getDataId();
                JSONObject data = paasFormDataEntityExt.getData();
                Double amount = getDoubleOrDefaultFromFormData(data, InvoiceEnum.TOTAL_MONEY.getAttr(), 0D);
                Double redAmount = redTotalMoneyByIdMap.get(dataId);
                if(redAmount != null && amount != null){
                    //判断该发票是否还允许红冲
                    double money = amount + redAmount;
                    if(money <= 0){
                        iterator.remove();
                    }
                }
            }
            total = (int)esEntities.getTotalElements();
        }
        PaasFormExplainEntity paasFormExplainEntity = paasFormExplainModel.getByBusinessType4Distributor(XbbRefTypeEnum.INVOICE.getCode(), corpid, invoiceGetByContractDTO.getDistributorMark());
        List<FieldAttrEntity> explainList = JSONArray.parseArray(paasFormExplainEntity.getExplains(), FieldAttrEntity.class);
        Integer businessType = paasFormExplainEntity.getBusinessType();
        //fieldList处理
        List<String> fieldList = BusinessFieldEnum.getByBusinessType(businessType);
        fieldList = saasListHelp.dealFieldList(fieldList, businessType, XbbRefTypeEnum.REFUND.getCode(), null);
        PaasFormEntityExt paasFormEntityExt = new PaasFormEntityExt();
        paasFormEntityExt.setBusinessName(XbbRefTypeEnum.getByCode(businessType).getName());
        paasFormEntityExt.setMainAttr(RefundEnum.REFUND_NO.getAttr());
        paasFormEntityExt.setMenuId(paasFormExplainEntity.getMenuId());
        paasFormEntityExt.setId(paasFormExplainEntity.getFormId());
        paasFormEntityExt.setAppId(paasFormExplainEntity.getAppId());
        paasFormEntityExt.setBusinessType(paasFormExplainEntity.getBusinessType());
        explainList = explainHelp.handleExplain(explainList, fieldList, paasFormEntityExt);
        invoiceGetByCustomerVO.setHeadList(explainList);
        invoiceGetByCustomerVO.setPaasFormDataESList(results);
        invoiceGetByCustomerVO.setForm(paasFormEntityExt);
        invoiceGetByCustomerVO.setBusinessType(XbbRefTypeEnum.INVOICE.getCode());
        //分页信息
        PageHelper pageHelper = PageHelperUtil.initPageHelper(total, invoiceGetByContractDTO.getPage(), invoiceGetByContractDTO.getPageSize(), PageConstant.DEFAULT_PAGE_SIZE);
        invoiceGetByCustomerVO.setPageHelper(pageHelper);
        //作废/红冲按钮权限信息
        JSONObject invoiceCancelRedPermission = new JSONObject();
        invoiceCancelRedPermission.put(ProPermissionAliasEnum.INVOICE_CANCEL.getAlias(), permSet.contains(ProPermissionAliasEnum.INVOICE_CANCEL.getAlias()));
        invoiceCancelRedPermission.put(ProPermissionAliasEnum.INVOICE_RED.getAlias(), permSet.contains(ProPermissionAliasEnum.INVOICE_RED.getAlias()));
        invoiceGetByCustomerVO.setInvoiceCancelRedPermission(invoiceCancelRedPermission);
        // 新建权限
        VerifyAddPermissionDTO verifyAddPermissionDTO = new VerifyAddPermissionDTO();
        // 这里只有赋值，没有copy
        verifyAddPermissionDTO.setSaasMark(paasFormExplainEntity.getSaasMark());
        verifyAddPermissionDTO.setBusinessType(businessType);
        verifyAddPermissionDTO.setMenuId(paasFormExplainEntity.getMenuId());
        verifyAddPermissionDTO.setLoginUser(invoiceGetByContractDTO.getLoginUser());
        verifyAddPermissionDTO.setSaasMark(paasFormExplainEntity.getSaasMark());
        verifyAddPermissionDTO.setCorpid(corpid);
        List<ButtonPojo> buttonList = paasFormHelp.getAddButton(verifyAddPermissionDTO, paasFormExplainEntity.getAppId(), paasFormExplainEntity.getFormId());
        invoiceGetByCustomerVO.setTopPermissions(buttonList);
        return invoiceGetByCustomerVO;
    }

    /**
     * 获取正常发票列表
     * @param corpid 公司ID
     * @param contractIds 合同ID数组
     * @param invoiceGetByContractDTO 入参
     * @throws XbbException error
     * @return es查询结果
     */
    private XbbAggregatedPage<PaasFormDataEntityExt> getNormalInvoiceListByEs(String corpid, List<Long> contractIds, InvoiceGetByContractDTO invoiceGetByContractDTO) throws XbbException {
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        BoolQueryBuilder teamQueryBuilder = boolQuery();
        teamQueryBuilder.filter(termQuery("corpid.keyword", corpid));
        List<ConditionsEntityExt> conditions = new ArrayList<>();
        //数据权限判断
        saasListDataPermissionHelp.listDataPermission(conditions, invoiceGetByContractDTO.getLoginUser(), XbbRefTypeEnum.INVOICE.getCode(), XbbRefTypeEnum.INVOICE.getCode());
        EsUtil.parseCondition(boolQueryBuilder, conditions, null, corpid, XbbRefTypeEnum.INVOICE.getCode());
        boolQueryBuilder.filter(termQuery("corpid.keyword", corpid));
        boolQueryBuilder.filter(termsQuery("data." + InvoiceEnum.CONTRACT_ID.getAttr() + ".keyword", contractIds));
        boolQueryBuilder.filter(termQuery("del", 0));
        boolQueryBuilder.filter(termQuery("data." + InvoiceEnum.IS_CANCEL.getAttr(), 0));
        boolQueryBuilder.filter(termQuery("data." + InvoiceEnum.IS_RED.getAttr(), 0));
        boolQueryBuilder.filter(termsQuery("flowStatus",Arrays.asList(FlowStatusEnum.NOT_NEED_APPROVAL.getType(), FlowStatusEnum.PASS.getType())));
        String serialNo = invoiceGetByContractDTO.getSerialNo();
        if(serialNo != null && !Objects.equals(serialNo, "")){
            boolQueryBuilder.filter(matchPhraseQuery("serialNo", serialNo));
        }
        boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD,IndexTypeEnum.IDX_SAAS_INVOICE.getType()));
        sourceBuilder.query(boolQueryBuilder);
        SearchRequest searchRequest = new SearchRequest(IndexTypeEnum.IDX_SAAS_INVOICE.getIndex());
        PageRequest pageRequest = EsUtil.setPage(sourceBuilder, invoiceGetByContractDTO.getPage(), invoiceGetByContractDTO.getPageSize());
        searchRequest.source(sourceBuilder);
        return xbbElasticsearchRestTemplate.queryForPages(pageRequest, searchRequest, PaasFormDataEntityExt.class);
    }

    /**
     * 获取合同ID和合同未开票金额对应关系
     *
     * @param xbbRefTypeEnum         业务类型
     * @param paasFormDataEntityExts 实体集合
     * @param corpid                 公司ID
     * @author zhouwq
     * @date 2020/1/8 19:24
     */
    private void getContractIdToInvoiceAmountMap(XbbRefTypeEnum xbbRefTypeEnum, List<PaasFormDataEntityExt> paasFormDataEntityExts, String corpid,Map<Long,Double> contractIdToUnInvoiceAmountMap,Map<Long,Double> refIdToUnInvoiceAmountMap,Map<String,List<PaasFormDataEntityExt>> paymentSheetMap) throws XbbException {
        Set<Long> contractIds = new HashSet<>();
        Set<Long> refIds = new HashSet<>();
        List<PaasFormDataEntityExt> paasFormDataEntityList =  new ArrayList<>();
        Map<String, Object> map = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        map.put(StringConstant.CORPID, corpid);
        map.put("del",BasicConstant.ZERO);
        map.put("isCancel",BasicConstant.ZERO);
        switch (xbbRefTypeEnum) {
            case CONTRACT:
                for (PaasFormDataEntityExt paasFormDataEntityExt : paasFormDataEntityExts) {
                    contractIds.add(paasFormDataEntityExt.getId());
                }
                break;
            case PAYMENT:
                for (PaasFormDataEntityExt paasFormDataEntityExt : paasFormDataEntityExts) {
                    JSONObject dataList = paasFormDataEntityExt.getData();
                    JSONArray contractArr = FastJsonHelper.getJsonArrOrDefaultFromFormData(dataList, PaymentEnum.CONTRACT.getAttr(), new JSONArray());
                    if (contractArr.isEmpty()) {
                        throw new XbbException(SystemErrorCodeEnum.API_ERROR_100028, ErrorMessageConstant.CONTRACT_LINK_CUSTOMER);
                    }
                    Long contractId = contractArr.getJSONObject(BasicConstant.ZERO).getLong(StringConstant.SAAS_LINK_BUSINESS_ID);
                    contractIds.add(contractId);
                    refIds.add(paasFormDataEntityExt.getId());
                }
                map.put("paymentIdIn",refIds);
                break;
            case PAYMENT_SHEET:
                for (PaasFormDataEntityExt paasFormDataEntityExt : paasFormDataEntityExts) {
                    JSONObject dataList = paasFormDataEntityExt.getData();
                    String status = FastJsonHelper.getStringOrDefaultFromFormData(paasFormDataEntityExt.getData(), PaymentSheetEnum.PAYMENT_SHEET_TYPE.getAttr(), PaymentSheetTypeEnum.WRITE_OFF.getCode());
                    boolean isPrePaymentSheet = Objects.equals(status,PaymentSheetTypeEnum.PREPAYMENT.getCode()) || Objects.equals(status,PaymentSheetTypeEnum.RED_PREPAYMENT.getCode()) ;
                    if(!isPrePaymentSheet){
                        JSONArray contractArr = FastJsonHelper.getJsonArrOrDefaultFromFormData(dataList, PaymentSheetEnum.CONTRACT.getAttr(), new JSONArray());
                        if (contractArr.isEmpty()) {
                            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100028, ErrorMessageConstant.PAYMENT_SHEET_LINK_CONTRACT);
                        }
                        for(int i = 0;i<contractArr.size();i++){
                            Long contractId = contractArr.getJSONObject(i).getLong(StringConstant.SAAS_LINK_BUSINESS_ID);
                            contractIds.add(contractId);
                        }
                        if(Objects.equals(paasFormDataEntityExt.getAlone(),SheetAloneEnum.PARENT.getCode())){
                            if(paymentSheetMap.containsKey(paasFormDataEntityExt.getUuid())){
                                List<PaasFormDataEntityExt> subPaasFormDataEntityList = paymentSheetMap.get(paasFormDataEntityExt.getUuid());
                                subPaasFormDataEntityList.forEach(item -> refIds.add(item.getId()));
                                paasFormDataEntityList.addAll(subPaasFormDataEntityList);
                            }else {
                                //容错
                                refIds.add(paasFormDataEntityExt.getId());
                                paasFormDataEntityList.add(paasFormDataEntityExt);
                            }
                        }else {
                            refIds.add(paasFormDataEntityExt.getId());
                            paasFormDataEntityList.add(paasFormDataEntityExt);
                        }
                    }else {
                        refIds.add(paasFormDataEntityExt.getId());
                        paasFormDataEntityList.add(paasFormDataEntityExt);
                    }
                }
                map.put("paymentSheetIdIn",refIds);
                if(CollectionsUtil.isNotEmpty(paasFormDataEntityList)) {
                    paasFormDataEntityExts = paasFormDataEntityList;
                }
                break;
            default:
                return;
        }
        List<PaasFormDataEntityExt> paasFormList = null;
        Map<String, Object> params = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        params.put(StringConstant.CORPID, corpid);
        if(!Objects.equals(xbbRefTypeEnum,XbbRefTypeEnum.CONTRACT)) {
            params.put(StringConstant.IDIN, contractIds);
            List<ContractEntityExt> contracts = contractModel.findEntitys(params);
            paasFormList = JSONArray.parseArray(JSONArray.toJSONString(contracts),PaasFormDataEntityExt.class);
        }else {
            paasFormList = paasFormDataEntityExts;
        }
        params.remove(StringConstant.IDIN);
        params.put("contractIdIn", contractIds);
        params.put("del",BasicConstant.ZERO);
        params.put("isCancel",BasicConstant.ZERO);
        List<InvoiceRelationshipEntity> relationshipEntityList = invoiceRelationshipModel.findEntitys(params);
        Map<Long, Double> contractInvoiceAmountMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long, Double> refInvoiceAmountMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        if(CollectionsUtil.isNotEmpty(relationshipEntityList)){
            for(InvoiceRelationshipEntity invoiceRelationshipEntity : relationshipEntityList){
                saasSaveHelp.addMapNormal(contractInvoiceAmountMap,invoiceRelationshipEntity.getContractId(),invoiceRelationshipEntity.getMoney());
            }
        }
        if(CollectionsUtil.isNotEmpty(paasFormList)){
            for(PaasFormDataEntityExt paasFormDataEntityExt : paasFormList){
                JSONObject data = paasFormDataEntityExt.getData();
                if (data != null) {
                    double amount = data.getDouble(ContractEnum.AMOUNT.getAttr());
                    double invoiceAmount = contractInvoiceAmountMap.getOrDefault(paasFormDataEntityExt.getId(),0D);
                    contractIdToUnInvoiceAmountMap.put(paasFormDataEntityExt.getId(),Arith.sub(amount,invoiceAmount));
                }
            }
        }
        if(!Objects.equals(xbbRefTypeEnum,XbbRefTypeEnum.CONTRACT)) {
            List<InvoiceRelationshipEntity> relationshipList = invoiceRelationshipModel.findEntitys(map);
            if(CollectionsUtil.isNotEmpty(relationshipList)){
                for(InvoiceRelationshipEntity invoiceRelationshipEntity : relationshipList){
                    if(Objects.equals(xbbRefTypeEnum,XbbRefTypeEnum.PAYMENT)){
                        saasSaveHelp.addMapNormal(refInvoiceAmountMap,invoiceRelationshipEntity.getPaymentId(),invoiceRelationshipEntity.getMoney());
                    }else if(Objects.equals(xbbRefTypeEnum,XbbRefTypeEnum.PAYMENT_SHEET)){
                        saasSaveHelp.addMapNormal(refInvoiceAmountMap,invoiceRelationshipEntity.getPaymentSheetId(),invoiceRelationshipEntity.getMoney());
                    }
                }
            }
        }
        if(CollectionsUtil.isNotEmpty(paasFormDataEntityExts)){
            for(PaasFormDataEntityExt paasFormDataEntityExt : paasFormDataEntityExts){
                JSONObject data = paasFormDataEntityExt.getData();
                if (data != null) {
                    double amount = 0D;
                    if(Objects.equals(xbbRefTypeEnum,XbbRefTypeEnum.PAYMENT)){
                        amount = data.getDouble(PaymentEnum.AMOUNT.getAttr());
                    }else if(Objects.equals(xbbRefTypeEnum,XbbRefTypeEnum.PAYMENT_SHEET)){
                        String type = FastJsonHelper.getStringOrDefaultFromFormData(data, PaymentSheetEnum.PAYMENT_SHEET_TYPE.getAttr(), PaymentSheetTypeEnum.WRITE_OFF.getCode());
                        amount = FundHelp.getSheetAmount4PaymentSheet(data, type);
                    }
                    double invoiceAmount = refInvoiceAmountMap.getOrDefault(paasFormDataEntityExt.getId(),0D);
                    refIdToUnInvoiceAmountMap.put(paasFormDataEntityExt.getId(),Arith.sub(amount,invoiceAmount));
                }
            }
        }

        /*contracts.forEach(e -> {
            JSONObject object = e.getData();
            if (object != null) {
                results.put(e.getId(), object.getDouble(ContractEnum.UN_INVOICE_AMOUNT.getAttr()));
            }
        });*/
    }

    /*private Map<Long, Double> getContractIdToInvoiceAmountMap(XbbRefTypeEnum xbbRefTypeEnum, PaasFormDataEntityExt paasFormDataEntityExt, String corpid) throws XbbException {
        List<PaasFormDataEntityExt> paasFormDataEntityExts = Collections.singletonList(paasFormDataEntityExt);
        return getContractIdToInvoiceAmountMap(xbbRefTypeEnum, paasFormDataEntityExts, corpid);
    }*/


    /**
     * 发票关联的业务数据如果删除需要先判断一下是否有发票
     * @param idList
     * @param xbbRefTypeEnum
     */
    @Override
   public void checkBusinessDeleteHaveInvoice(List<Long> idList,String corpid,XbbRefTypeEnum xbbRefTypeEnum,Collection<String> errorTypeSet,Collection<String> errorDataSet,Collection<Long> delIdList, Collection<String> delNoList,Map<String,Long> parentMap,Map<Long,String> parentSerialNoMap,Map<Long,String> subMap,Map<String,List<Long>> uuidSubMap,Map<String,List<String>> uuidSerialNoMap){
        //判断这些回款单下面是否存在发票
        Map<String,Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        String noneDelMsg = "";
        if(Objects.equals(xbbRefTypeEnum,XbbRefTypeEnum.PAYMENT_SHEET)){
            param.put("paymentSheetIdIn",idList);
            noneDelMsg = I18nMessageUtil.getMessage(ErrorMessageConstant.HAVE_PAYMENT_SHEET_INVOICE_NOT_DEL);
        }else if(Objects.equals(xbbRefTypeEnum,XbbRefTypeEnum.PAYMENT)){
            param.put("paymentIdIn",idList);
            noneDelMsg = I18nMessageUtil.getMessage(ErrorMessageConstant.HAVE_PAYMENT_INVOICE_NOT_DEL);
        }else{
            return;
        }
        param.put("corpid",corpid);
        param.put("del",BasicConstant.ZERO);
        List<InvoiceRelationshipEntity> invoiceRelationshipEntityList = invoiceRelationshipModel.findEntitys(param);
        Set<Long> refIdSet = new HashSet<>();
        Set<String> refSerialNoSet = new HashSet<>();
        //根据idList 所有会删除的回款单计划去查询是否有存在发票,只要回款单存在发票,其他子回款单也不允许删除
        if(CollectionsUtil.isNotEmpty(invoiceRelationshipEntityList)) {
            invoiceRelationshipEntityList.forEach(invoiceRelationshipEntity -> {
                if(Objects.equals(xbbRefTypeEnum,XbbRefTypeEnum.PAYMENT_SHEET)){
                    if(parentSerialNoMap.containsKey(invoiceRelationshipEntity.getPaymentSheetId())){
                        refIdSet.add(invoiceRelationshipEntity.getPaymentSheetId());
                        refSerialNoSet.add(invoiceRelationshipEntity.getPaymentSheetNo());
                    }else {
                        String uuid = subMap.getOrDefault(invoiceRelationshipEntity.getPaymentSheetId(),"");
                        //放入其他子回款单
                        List<Long> allSubId =uuidSubMap.get(uuid);
                        List<String> allSubSerialNo = uuidSerialNoMap.get(uuid);
                        refIdSet.addAll(allSubId);
                        refSerialNoSet.addAll(allSubSerialNo);
                        Long parentId = parentMap.getOrDefault(uuid,0L);
                        String parentSerialNo = parentSerialNoMap.getOrDefault(parentId,"");
                        refIdSet.add(parentId);
                        refSerialNoSet.add(parentSerialNo);
                    }
                }else if(Objects.equals(xbbRefTypeEnum,XbbRefTypeEnum.PAYMENT)){
                    refIdSet.add(invoiceRelationshipEntity.getPaymentId());
                    refSerialNoSet.add(invoiceRelationshipEntity.getPaymentNo());
                }
            });
            commonHelp.removeInvoiceRefNoneDel(noneDelMsg, refIdSet, refSerialNoSet, errorTypeSet, errorDataSet, delIdList, delNoList, idList);
        }
    }

   @Override
   public InvoiceAmountDetailVO getInvoiceAmountDetail(InvoiceAmountDetailGetDTO invoiceAmountDetailGetDTO) throws XbbException {
        return invoiceModel.getInvoiceAmountDetail(invoiceAmountDetailGetDTO);
   }

    @Override
    public void updateBatchLabelAttr(AddLabelDTO addLabelDTO, List<PaasFormDataEntityExt> addBatchList, Boolean addOrDelete) throws XbbException {
        InvoiceUpdateBatchDTO invoiceUpdateBatchDTO = new InvoiceUpdateBatchDTO();
        BeanUtil.copyProperties(addLabelDTO, invoiceUpdateBatchDTO);
        List<InvoiceUpdateDTO> invoiceList = new ArrayList<>();
        addBatchList.forEach(item ->{
            InvoiceUpdateDTO invoiceUpdateDTO = new InvoiceUpdateDTO();
            invoiceUpdateDTO.setData(item.getData());
            invoiceUpdateDTO.setId(item.getId());
            invoiceList.add(invoiceUpdateDTO);
        });
        invoiceUpdateBatchDTO.setInvoiceList(invoiceList);
        updateBatch(invoiceUpdateBatchDTO);

    }

    @Override
    public void afterSaveForWorkflow(SaasFormSaveDTO saasFormSaveDTO) throws XbbException {
        String corpid = saasFormSaveDTO.getCorpid();
        JSONObject newData = saasFormSaveDTO.getNewData();
        JSONObject oldData = saasFormSaveDTO.getOldData();
        Long originId = FastJsonHelper.getLongOrDefaultFromFormData(newData, InvoiceEnum.ORIGIN_ID.getAttr(), 0L);
        PaasFormDataEntity newPaasFormDataEntity = saasFormSaveDTO.getNewPaasFormDataEntity();
        Long invoiceId = newPaasFormDataEntity.getId();

//        InvoiceRelationshipEditPojo invoiceRelationshipEditPojo = getAddOrDeleteRelationship(newData,oldData,corpid,invoiceId);
//        //开票的金额
//        try {
        //新增失败的发票es回滚，在外部insert内已处理（直接物理删除es）
//        if (originId > BasicConstant.ZERO) {
//            JSONObject jsonObject = new JSONObject();
//            jsonObject.put(InvoiceEnum.HAS_RED.getAttr(), BasicConstant.ONE);
//            UpdateDataEntity updateData = ExplainUtil.getUpdateData(originId, jsonObject, corpid);
//            invoiceModel.updateBatch(Collections.singletonList(updateData), corpid);
//
//            jsonObject = new JSONObject();
//            jsonObject.put(InvoiceEnum.IS_RED.getAttr(), BasicConstant.ONE);
//            UpdateDataEntity updateData1 = ExplainUtil.getUpdateData(invoiceId, jsonObject, corpid);
//            invoiceModel.updateBatch(Collections.singletonList(updateData1), corpid);
//        }
//        } catch (XbbException e) {
//            rollBack4LinkEs(null, corpid, invoiceRelationshipEditPojo.getContractIdList(), invoiceRelationshipEditPojo.getPaymentIdList(), invoiceRelationshipEditPojo.getPaymentSheetIdList());
//            LOG.error("invoiceServiceImp.afterSave 执行出错：", e);
//            throw e;
//        }catch (Exception e){
//            rollBack4LinkEs(null, corpid, invoiceRelationshipEditPojo.getContractIdList(), invoiceRelationshipEditPojo.getPaymentIdList(), invoiceRelationshipEditPojo.getPaymentSheetIdList());
//            LOG.error("invoiceServiceImp.afterSave 执行出错：", e);
//            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
//        }
    }

    @Override
    public void afterSaveForUpdateWorkflow(SaasFormSaveDTO saasFormSaveDTO) throws XbbException {

    }

}
